platform-driver-x86.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems
@ 2020-10-27 13:49 Divya Bharathi
  2020-10-28  9:57 ` Hans de Goede
  2020-10-29  8:01 ` Mauro Carvalho Chehab
  0 siblings, 2 replies; 6+ messages in thread
From: Divya Bharathi @ 2020-10-27 13:49 UTC (permalink / raw)
  To: dvhart
  Cc: LKML, platform-driver-x86, Divya Bharathi, Hans de Goede,
	Andy Shevchenko, mark gross, Mario Limonciello, Prasanth KSR

The Dell WMI Systems Management Driver provides a sysfs
interface for systems management to enable BIOS configuration
capability on certain Dell Systems.

This driver allows user to configure Dell systems with a
uniform common interface. To facilitate this, the patch
introduces a generic way for driver to be able to create
configurable BIOS Attributes available in Setup (F2) screen.

Cc: Hans de Goede <hdegoede@redhat.com>
Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: mark gross <mgross@linux.intel.com>

Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
Co-developed-by: Prasanth KSR <prasanth.ksr@dell.com>
Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
Signed-off-by: Divya Bharathi <divya.bharathi@dell.com>
---

Changes from v6 to v7:
 - Set current_value to rw only for root user
 - Correct spacing in sysfs documentation
 - Make some more attributes mandatory
 - Remove cap_sys_admin check
 - add extra check for -ENOMEM for attribute_property_store
 - Add dereferencing check for data types read
 - Adjust passobj bounds check by 1
 - Add extra check for -ENOMEM in new_password_store
 - Clear current password properly
 - Simplify reset_bios_store
 - Adjust helper functions per Hans' suggestions
 - Correct integer handling abusing ACPI core

Changes from v5 to v6:
 - Fixed Mutex bug in set_bios_defaults
 - Adjust wrapping for enum-attributes.c description
 - Adjust wrapping for int-attributes.c comparison
 - Make current_password mandatory for mechanism == password
 - Move strlen of admin check into populate_security_password
 - Use correct device for dev_err calls (bios_attr_wdev)
 - Remove type from structs and add type-string directly in show functions
 - Remove unneeded macro definition (make function static)
 - Make calls to get_*_instance_id error handling match kernel style
 - Adjust -AE_ERROR to -EIO
 - Adjust validate_integer_input to propagate errors
 - Make current_password_store return -EIO for an unknown type
 - Don't store current_value, read dynamically every time
 - Move kobject_uevents to class_dev
 - Update all kernel doc comments with standard termination '*/'
 - Correct dereferences in alloc_*_data()
 - Make value_modifier and value_modifier_count local
 - Remove is_enabled from po
 - Fix current_password_store const char* handling
 - Propagate error value from get_po_instance_id() in is_enabled_show()
 - Adjust validate_str_input
 - Cleanups to reset_bios_store to use sysfs_match_string
 - Adjust set_bios_defaults
 - Rename create_reset_bios
 - strlcpy_attr handling
 - Check number of kset_unregister calls in error path
 - Make teardown order match error order
 - Pass password into calculate_security_buffer
 - Correct handling of const char * values in macros
 - Add new function for populating string buffers
 - Switch strncasecmp to strcasecmp
   + This wasn't strictly necessary (the firmware rejected invalid strings)
   + However, by doing it in the kernel we can send a more sensbile error -EINVAL

Changes from v4 to v5:
 - Correct Kconfig description to not use "WMI" twice.
 - s/is_authentication_set/is_enabled/
 - Specify that all attributes are optional and take UTF8
 - Change authentication type to "role" and "mechanism"
 - Explain what semicolons are
 - Adjust whitespace of documentation

Changes from v3 to v4:
 - Create a firmware-attributes class and tie ksets to a virtual device in it
 - Make modifier and value_modifier "dell only" attributes.
 - Correct some errors caught by kernel build bot around missing prototypes
 - Remove mutexes from populate_* functions and put in init_dell_bios_attrib_wmi instead
 - Move all code into a subdirectory drivers/platform/x86/dell-wmi-sysman and remove dell-wmi-*
   prefix on files
 - Move all data structures into shared struct
 - In alloc functions instead of kzalloc use kcalloc and check that there is no overflow
   + Same check for other alloc_foo-data functions
 -  populate_*: Move sysfs_create_group to end of the function to prevent race conditions
 - Save kernel object into each data instance and only remove that rather than sysfs_remove_group
 - Document in sysfs file what causes change uevents to come through
 - Only notify with change uevent one time on multiple settings modifications
 - Adjust lots of string handling
 - Make more objects static
 - Various whitespace corrections
 - Document map_wmi_error properly
 - Bump version to 5.11 (February 2021)

Changes from v2 to v3:
 - Fix a possible NULL pointer error in init
 - Add missing newlines to all dev_err/dev_dbg/pr_err/pr_debug statements
 - Correct updating passwords when both Admin and System password are set
 - Correct the WMI driver name
 - Correct some namespace clashing when compiled into the kernel (Reported by Mark Gross)
 - Correct some comment typos
 - Adopt suggestions made by Hans:
   + Use single global mutex
   + Clarify reason for uevents with a comment
   + Remove functions for set and get current password
   + Rename lower_bound to min_value and upper_bound to max_value
   + Rename possible_value to possible_values
   + Remove references to float
   + Build a separate passwords directory again since it behaves differently from the other
     attributes
   + Move more calls from pr_err -> dev_err
 - Documentation cleanups (see v2 patch feedback)
   + Grouping types
   + Syntax of `modifier` output

Changes from v1 to v2:
 - use pr_fmt instead of pr_err(DRIVER_NAME
 - re-order variables reverse xmas tree order
 - correct returns of -1 to error codes
 - correct usage of {} on some split line statements
 - Refine all documentation deficiencies suggested by Hans
 - Merge all attributes to a single directory
 - Overhaul WMI interface interaction as suggested by Hans
   * Move WMI driver registration to start of module
   * Remove usage of lists that only use first entry for WMI interfaces
   * Create a global structure shared across interface source files
   * Make get_current_password function static
   * Remove get_pending changes function, shared across global structure now.
 - Overhaul use of mutexes
   * Make kset list mutex shared across source files
   * Remove unneeded dell-wmi-sysman call_mutex
   * Keep remaining call_mutexes in WMI functions
 - Move security area calculation into a function
 - Use NLS helper for utf8->utf16 conversion

 .../testing/sysfs-class-firmware-attributes   | 223 +++++++
 MAINTAINERS                                   |   8 +
 drivers/platform/x86/Kconfig                  |  12 +
 drivers/platform/x86/Makefile                 |   1 +
 drivers/platform/x86/dell-wmi-sysman/Makefile |   8 +
 .../x86/dell-wmi-sysman/biosattr-interface.c  | 186 ++++++
 .../x86/dell-wmi-sysman/dell-wmi-sysman.h     | 191 ++++++
 .../x86/dell-wmi-sysman/enum-attributes.c     | 187 ++++++
 .../x86/dell-wmi-sysman/int-attributes.c      | 171 +++++
 .../x86/dell-wmi-sysman/passobj-attributes.c  | 192 ++++++
 .../dell-wmi-sysman/passwordattr-interface.c  | 153 +++++
 .../x86/dell-wmi-sysman/string-attributes.c   | 157 +++++
 drivers/platform/x86/dell-wmi-sysman/sysman.c | 625 ++++++++++++++++++
 13 files changed, 2114 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-class-firmware-attributes
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/Makefile
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/int-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/string-attributes.c
 create mode 100644 drivers/platform/x86/dell-wmi-sysman/sysman.c

diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
new file mode 100644
index 000000000000..feee3b860e5a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
@@ -0,0 +1,223 @@
+What:		/sys/class/firmware-attributes/*/attributes/*/
+Date:		February 2021
+KernelVersion:	5.11
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+Description:
+		A sysfs interface for systems management software to enable
+		configuration capability on supported systems.  This directory
+		exposes interfaces for interacting with configuration options.
+
+		Unless otherwise specified in an attribute description all attributes are optional
+		and will accept UTF-8 input.
+
+		type: A file that can be read to obtain the type of attribute.  This attribute is
+			mandatory.
+
+		The following are known types:
+			- enumeration: a set of pre-defined valid values
+			- integer: a range of numerical values
+			- string
+
+		All attribute types support the following values:
+
+		current_value:	A file that can be read to obtain the current
+				value of the <attr>.
+
+				This file can also be written to in order to update the value of a
+				<attr>
+
+				This attribute is mandatory.
+
+		default_value:	A file that can be read to obtain the default
+				value of the <attr>
+
+		display_name:	A file that can be read to obtain a user friendly
+				description of the at <attr>
+
+		display_name_language_code:	A file that can be read to obtain
+						the IETF language tag corresponding to the
+						"display_name" of the <attr>
+
+		"enumeration"-type specific properties:
+
+		possible_values:	A file that can be read to obtain the possible
+					values of the <attr>. Values are separated using
+					semi-colon (``;``).
+
+		"integer"-type specific properties:
+
+		min_value:	A file that can be read to obtain the lower
+				bound value of the <attr>
+
+		max_value:	A file that can be read to obtain the upper
+				bound value of the <attr>
+
+		scalar_increment:	A file that can be read to obtain the scalar value used for
+					increments of current_value this attribute accepts.
+
+		"string"-type specific properties:
+
+		max_length:	A file that can be read to obtain the maximum
+				length value of the <attr>
+
+		min_length:	A file that can be read to obtain the minimum
+				length value of the <attr>
+
+		Dell specific class extensions
+		--------------------------
+
+		On Dell systems the following additional attributes are available:
+
+		dell_modifier:	A file that can be read to obtain attribute-level
+				dependency rule. It says an attribute X will become read-only or
+				suppressed, if/if-not attribute Y is configured.
+
+				modifier rules can be in following format:
+				[ReadOnlyIf:<attribute>=<value>]
+				[ReadOnlyIfNot:<attribute>=<value>]
+				[SuppressIf:<attribute>=<value>]
+				[SuppressIfNot:<attribute>=<value>]
+
+				For example:
+				AutoOnFri/dell_modifier has value,
+					[SuppressIfNot:AutoOn=SelectDays]
+
+				This means AutoOnFri will be suppressed in BIOS setup if AutoOn
+				attribute is not "SelectDays" and its value will not be effective
+				through sysfs until this rule is met.
+
+		Enumeration attributes also support the following:
+
+		dell_value_modifier:	A file that can be read to obtain value-level dependency.
+					This file is similar to dell_modifier but here,	an
+					attribute's current value will be forcefully changed based
+					dependent attributes value.
+
+					dell_value_modifier rules can be in following format:
+					<value>[ForceIf:<attribute>=<value>]
+					<value>[ForceIfNot:<attribute>=<value>]
+
+					For example,
+					LegacyOrom/dell_value_modifier has value:
+						Disabled[ForceIf:SecureBoot=Enabled]
+					This means LegacyOrom's current value will be forced to
+					"Disabled" in BIOS setup if SecureBoot is Enabled and its
+					value will not be effective through sysfs until this rule is
+					met.
+
+What:		/sys/class/firmware-attributes/*/authentication/
+Date:		February 2021
+KernelVersion:	5.11
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+
+		Devices support various authentication mechanisms which can be exposed
+		as a separate configuration object.
+
+		For example a "BIOS Admin" password and "System" Password can be set,
+		reset or cleared using these attributes.
+		- An "Admin" password is used for preventing modification to the BIOS
+		  settings.
+		- A "System" password is required to boot a machine.
+
+		Change in any of these two authentication methods will also generate an
+		uevent KOBJ_CHANGE.
+
+		is_enabled:		A file that can be read to obtain a 0/1 flag to see if
+					<attr> authentication is enabled.
+
+		role:			The type of authentication used.
+					This attribute is mandatory.
+					Known types:
+						bios-admin: Representing BIOS administrator password
+						power-on: Representing a password required to use
+							  the system
+
+		mechanism:		The means of authentication.  This attribute is mandatory.
+					Only supported type currently is "password".
+
+		max_password_length:	A file that can be read to obtain the
+					maximum length of the Password
+
+		min_password_length:	A file that can be read to obtain the
+					minimum length of the Password
+
+		current_password:	A write only value used for privileged access such as
+					setting	attributes when a system or admin password is set
+					or resetting to a new password
+
+					This attribute is mandatory when mechanism == "password".
+
+		new_password:		A write only value that when used in tandem with
+					current_password will reset a system or admin password.
+
+		Note, password management is session specific. If Admin password is set,
+		same password must be written into current_password file (required for
+		password-validation) and must be cleared once the session is over.
+		For example:
+			echo "password" > current_password
+			echo "disabled" > TouchScreen/current_value
+			echo "" > current_password
+
+		Drivers may emit a CHANGE uevent when a password is set or unset
+		userspace may check it again.
+
+		On Dell systems, if Admin password is set, then all BIOS attributes
+		require password validation.
+
+What:		/sys/class/firmware-attributes/*/attributes/pending_reboot
+Date:		February 2021
+KernelVersion:	5.11
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+Description:
+		A read-only attribute reads 1 if a reboot is necessary to apply
+		pending BIOS attribute changes. Also, an uevent_KOBJ_CHANGE is
+		generated when it changes to 1.
+
+			0:	All BIOS attributes setting are current
+			1:	A reboot is necessary to get pending BIOS attribute changes
+				applied
+
+		Note, userspace applications need to follow below steps for efficient
+		BIOS management,
+		1.	Check if admin password is set. If yes, follow session method for
+			password management as briefed under authentication section above.
+		2.	Before setting any attribute, check if it has any modifiers
+			or value_modifiers. If yes, incorporate them and then modify
+			attribute.
+
+		Drivers may emit a CHANGE uevent when this value changes and userspace
+		may check it again.
+
+What:		/sys/class/firmware-attributes/*/attributes/reset_bios
+Date:		February 2021
+KernelVersion:	5.11
+Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
+		Mario Limonciello <mario.limonciello@dell.com>,
+		Prasanth KSR <prasanth.ksr@dell.com>
+Description:
+		This attribute can be used to reset the BIOS Configuration.
+		Specifically, it tells which type of reset BIOS configuration is being
+		requested on the host.
+
+		Reading from it returns a list of supported options encoded as:
+
+			'builtinsafe' (Built in safe configuration profile)
+			'lastknowngood' (Last known good saved configuration profile)
+			'factory' (Default factory settings configuration profile)
+			'custom' (Custom saved configuration profile)
+
+		The currently selected option is printed in square brackets as
+		shown below:
+
+		# echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
+		# cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
+		# builtinsafe lastknowngood [factory] custom
+
+		Note that any changes to this attribute requires a reboot
+		for changes to take effect.
diff --git a/MAINTAINERS b/MAINTAINERS
index e73636b75f29..e6e71444545a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4991,6 +4991,14 @@ M:	Mario Limonciello <mario.limonciello@dell.com>
 S:	Maintained
 F:	drivers/platform/x86/dell-wmi-descriptor.c
 
+DELL WMI SYSMAN DRIVER
+M:	Divya Bharathi <divya.bharathi@dell.com>
+M:	Mario Limonciello <mario.limonciello@dell.com>
+M:	Prasanth Ksr <prasanth.ksr@dell.com>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/dell-wmi-syman/*
+
 DELL WMI NOTIFICATIONS DRIVER
 M:	Matthew Garrett <mjg59@srcf.ucam.org>
 M:	Pali Rohár <pali@kernel.org>
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 0d91d136bc3b..7b6e90546b17 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -430,6 +430,18 @@ config DELL_WMI
 	  To compile this driver as a module, choose M here: the module will
 	  be called dell-wmi.
 
+config DELL_WMI_SYSMAN
+	tristate "Dell WMI-based Systems management driver"
+	depends on ACPI_WMI
+	depends on DMI
+	select NLS
+	help
+	  This driver allows changing BIOS settings on many Dell machines from
+	  2018 and newer without the use of any additional software.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called dell-wmi-sysman.
+
 config DELL_WMI_DESCRIPTOR
 	tristate
 	depends on ACPI_WMI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 5f823f7eff45..36ce38e80c8f 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_DELL_WMI)			+= dell-wmi.o
 obj-$(CONFIG_DELL_WMI_DESCRIPTOR)	+= dell-wmi-descriptor.o
 obj-$(CONFIG_DELL_WMI_AIO)		+= dell-wmi-aio.o
 obj-$(CONFIG_DELL_WMI_LED)		+= dell-wmi-led.o
+obj-$(CONFIG_DELL_WMI_SYSMAN)		+= dell-wmi-sysman/
 
 # Fujitsu
 obj-$(CONFIG_AMILO_RFKILL)	+= amilo-rfkill.o
diff --git a/drivers/platform/x86/dell-wmi-sysman/Makefile b/drivers/platform/x86/dell-wmi-sysman/Makefile
new file mode 100644
index 000000000000..825fb2fbeea8
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_DELL_WMI_SYSMAN)  += dell-wmi-sysman.o
+dell-wmi-sysman-objs := 	sysman.o		\
+				enum-attributes.o	\
+				int-attributes.o	\
+				string-attributes.o	\
+				passobj-attributes.o	\
+				biosattr-interface.o	\
+				passwordattr-interface.o
diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
new file mode 100644
index 000000000000..f95d8ddace5a
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to SET methods under BIOS attributes interface GUID for use
+ * with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include <linux/wmi.h>
+#include "dell-wmi-sysman.h"
+
+#define SETDEFAULTVALUES_METHOD_ID					0x02
+#define SETBIOSDEFAULTS_METHOD_ID					0x03
+#define SETATTRIBUTE_METHOD_ID						0x04
+
+static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
+					int method_id)
+{
+	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_buffer input;
+	union acpi_object *obj;
+	acpi_status status;
+	int ret = -EIO;
+
+	input.length =  (acpi_size) size;
+	input.pointer = in_args;
+	status = wmidev_evaluate_method(wdev, 0, method_id, &input, &output);
+	if (ACPI_FAILURE(status))
+		return -EIO;
+	obj = (union acpi_object *)output.pointer;
+	if (obj->type == ACPI_TYPE_INTEGER)
+		ret = obj->integer.value;
+
+	if (wmi_priv.pending_changes == 0) {
+		wmi_priv.pending_changes = 1;
+		/* let userland know it may need to check reboot pending again */
+		kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);
+	}
+	kfree(output.pointer);
+	return map_wmi_error(ret);
+}
+
+/**
+ * set_attribute() - Update an attribute value
+ * @a_name: The attribute name
+ * @a_value: The attribute value
+ *
+ * Sets an attribute to new value
+ */
+int set_attribute(const char *a_name, const char *a_value)
+{
+	size_t security_area_size, buffer_size;
+	size_t a_name_size, a_value_size;
+	char *buffer = NULL, *start;
+	int ret;
+
+	mutex_lock(&wmi_priv.mutex);
+	if (!wmi_priv.bios_attr_wdev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* build/calculate buffer */
+	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
+	a_name_size = calculate_string_buffer(a_name);
+	a_value_size = calculate_string_buffer(a_value);
+	buffer_size = security_area_size + a_name_size + a_value_size;
+	buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* build security area */
+	populate_security_buffer(buffer, wmi_priv.current_admin_password);
+
+	/* build variables to set */
+	start = buffer + security_area_size;
+	ret = populate_string_buffer(start, a_name_size, a_name);
+	if (ret < 0)
+		goto out;
+	start += ret;
+	ret = populate_string_buffer(start, a_value_size, a_value);
+	if (ret < 0)
+		goto out;
+
+	print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
+	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
+					    buffer, buffer_size,
+					    SETATTRIBUTE_METHOD_ID);
+	if (ret == -EOPNOTSUPP)
+		dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n");
+	else if (ret == -EACCES)
+		dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
+
+out:
+	kfree(buffer);
+	mutex_unlock(&wmi_priv.mutex);
+	return ret;
+}
+
+/**
+ * set_bios_defaults() - Resets BIOS defaults
+ * @deftype: the type of BIOS value reset to issue.
+ *
+ * Resets BIOS defaults
+ */
+int set_bios_defaults(u8 deftype)
+{
+	size_t security_area_size, buffer_size;
+	size_t integer_area_size = sizeof(u8);
+	char *buffer = NULL;
+	u8 *defaultType;
+	int ret;
+
+	mutex_lock(&wmi_priv.mutex);
+	if (!wmi_priv.bios_attr_wdev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
+	buffer_size = security_area_size + integer_area_size;
+	buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* build security area */
+	populate_security_buffer(buffer, wmi_priv.current_admin_password);
+
+	defaultType = buffer + security_area_size;
+	*defaultType = deftype;
+
+	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
+					    SETBIOSDEFAULTS_METHOD_ID);
+	if (ret)
+		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
+
+	kfree(buffer);
+out:
+	mutex_unlock(&wmi_priv.mutex);
+	return ret;
+}
+
+static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.bios_attr_wdev = wdev;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static int bios_attr_set_interface_remove(struct wmi_device *wdev)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.bios_attr_wdev = NULL;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static const struct wmi_device_id bios_attr_set_interface_id_table[] = {
+	{ .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID },
+	{ },
+};
+static struct wmi_driver bios_attr_set_interface_driver = {
+	.driver = {
+		.name = DRIVER_NAME
+	},
+	.probe = bios_attr_set_interface_probe,
+	.remove = bios_attr_set_interface_remove,
+	.id_table = bios_attr_set_interface_id_table,
+};
+
+int init_bios_attr_set_interface(void)
+{
+	return wmi_driver_register(&bios_attr_set_interface_driver);
+}
+
+void exit_bios_attr_set_interface(void)
+{
+	wmi_driver_unregister(&bios_attr_set_interface_driver);
+}
+
+MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
diff --git a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
new file mode 100644
index 000000000000..b80f2a62ea3f
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Definitions for kernel modules using Dell WMI System Management Driver
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#ifndef _DELL_WMI_BIOS_ATTR_H_
+#define _DELL_WMI_BIOS_ATTR_H_
+
+#include <linux/wmi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/capability.h>
+
+#define DRIVER_NAME					"dell-wmi-sysman"
+#define MAX_BUFF  512
+
+#define DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID	"F1DDEE52-063C-4784-A11E-8A06684B9BF5"
+#define DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BFA"
+#define DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BF9"
+#define DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID		"0894B8D6-44A6-4719-97D7-6AD24108BFD4"
+#define DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BF4"
+#define DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID		"70FE8229-D03B-4214-A1C6-1F884B1A892A"
+
+struct enumeration_data {
+	struct kobject *attr_name_kobj;
+	char display_name_language_code[MAX_BUFF];
+	char dell_value_modifier[MAX_BUFF];
+	char possible_values[MAX_BUFF];
+	char attribute_name[MAX_BUFF];
+	char default_value[MAX_BUFF];
+	char dell_modifier[MAX_BUFF];
+	char display_name[MAX_BUFF];
+};
+
+struct integer_data {
+	struct kobject *attr_name_kobj;
+	char display_name_language_code[MAX_BUFF];
+	char attribute_name[MAX_BUFF];
+	char dell_modifier[MAX_BUFF];
+	char display_name[MAX_BUFF];
+	int scalar_increment;
+	int default_value;
+	int min_value;
+	int max_value;
+};
+
+struct str_data {
+	struct kobject *attr_name_kobj;
+	char display_name_language_code[MAX_BUFF];
+	char attribute_name[MAX_BUFF];
+	char display_name[MAX_BUFF];
+	char default_value[MAX_BUFF];
+	char dell_modifier[MAX_BUFF];
+	int min_length;
+	int max_length;
+};
+
+struct po_data {
+	struct kobject *attr_name_kobj;
+	char attribute_name[MAX_BUFF];
+	int min_password_length;
+	int max_password_length;
+};
+
+struct wmi_sysman_priv {
+	char current_admin_password[MAX_BUFF];
+	char current_system_password[MAX_BUFF];
+	struct wmi_device *password_attr_wdev;
+	struct wmi_device *bios_attr_wdev;
+	struct kset *authentication_dir_kset;
+	struct kset *main_dir_kset;
+	struct device *class_dev;
+	struct enumeration_data *enumeration_data;
+	int enumeration_instances_count;
+	struct integer_data *integer_data;
+	int integer_instances_count;
+	struct str_data *str_data;
+	int str_instances_count;
+	struct po_data *po_data;
+	int po_instances_count;
+	bool pending_changes;
+	struct mutex mutex;
+};
+
+/* global structure used by multiple WMI interfaces */
+extern struct wmi_sysman_priv wmi_priv;
+
+enum { ENUM, INT, STR, PO };
+
+enum {
+	ATTR_NAME,
+	DISPL_NAME_LANG_CODE,
+	DISPLAY_NAME,
+	DEFAULT_VAL,
+	CURRENT_VAL,
+	MODIFIER
+};
+
+#define get_instance_id(type)							\
+static int get_##type##_instance_id(struct kobject *kobj)			\
+{										\
+	int i;									\
+	for (i = 0; i <= wmi_priv.type##_instances_count; i++) {		\
+		if (!(strcmp(kobj->name, wmi_priv.type##_data[i].attribute_name)))\
+			return i;						\
+	}									\
+	return -EIO;								\
+}
+
+#define attribute_s_property_show(name, type)					\
+static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,	\
+			   char *buf)						\
+{										\
+	int i = get_##type##_instance_id(kobj);					\
+	if (i >= 0)								\
+		return sprintf(buf, "%s\n", wmi_priv.type##_data[i].name);	\
+	return 0;								\
+}
+
+#define attribute_n_property_show(name, type)					\
+static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,	\
+			   char *buf)						\
+{										\
+	int i = get_##type##_instance_id(kobj);					\
+	if (i >= 0)								\
+		return sprintf(buf, "%d\n", wmi_priv.type##_data[i].name);	\
+	return 0;								\
+}
+
+#define attribute_property_store(curr_val, type)				\
+static ssize_t curr_val##_store(struct kobject *kobj,				\
+				struct kobj_attribute *attr,			\
+				const char *buf, size_t count)			\
+{										\
+	char *p, *buf_cp;							\
+	int i, ret = -EIO;							\
+	buf_cp = kstrdup(buf, GFP_KERNEL);					\
+	if (!buf_cp)								\
+		return -ENOMEM;							\
+	p = memchr(buf_cp, '\n', count);					\
+										\
+	if (p != NULL)								\
+		*p = '\0';							\
+	i = get_##type##_instance_id(kobj);					\
+	if (i >= 0)								\
+		ret = validate_##type##_input(i, buf_cp);			\
+	if (!ret)								\
+		ret = set_attribute(kobj->name, buf_cp);			\
+	kfree(buf_cp);								\
+	return ret ? ret : count;						\
+}
+
+union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
+int get_instance_count(const char *guid_string);
+void strlcpy_attr(char *dest, char *src);
+
+int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
+			struct kobject *attr_name_kobj);
+int alloc_enum_data(void);
+void exit_enum_attributes(void);
+
+int populate_int_data(union acpi_object *integer_obj, int instance_id,
+			struct kobject *attr_name_kobj);
+int alloc_int_data(void);
+void exit_int_attributes(void);
+
+int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj);
+int alloc_str_data(void);
+void exit_str_attributes(void);
+
+int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj);
+int alloc_po_data(void);
+void exit_po_attributes(void);
+
+int set_attribute(const char *a_name, const char *a_value);
+int set_bios_defaults(u8 defType);
+
+void exit_bios_attr_set_interface(void);
+int init_bios_attr_set_interface(void);
+int map_wmi_error(int error_code);
+size_t calculate_string_buffer(const char *str);
+size_t calculate_security_buffer(char *authentication);
+void populate_security_buffer(char *buffer, char *authentication);
+ssize_t populate_string_buffer(char *buffer, size_t buffer_len, const char *str);
+int set_new_password(const char *password_type, const char *new);
+int init_bios_attr_pass_interface(void);
+void exit_bios_attr_pass_interface(void);
+
+#endif
diff --git a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
new file mode 100644
index 000000000000..692c1f4777bf
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to enumeration type attributes under
+ * BIOS Enumeration GUID for use with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman.h"
+
+get_instance_id(enumeration);
+
+static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int instance_id = get_enumeration_instance_id(kobj);
+	union acpi_object *obj;
+	ssize_t ret;
+
+	if (instance_id < 0)
+		return instance_id;
+
+	/* need to use specific instance_id and guid combination to get right data */
+	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+	if (!obj)
+		return -EIO;
+	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING)
+		return -EINVAL;
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
+	kfree(obj);
+	return ret;
+}
+
+/**
+ * validate_enumeration_input() - Validate input of current_value against possible values
+ * @instance_id: The instance on which input is validated
+ * @buf: Input value
+ */
+static int validate_enumeration_input(int instance_id, const char *buf)
+{
+	char *options, *tmp, *p;
+	int ret = -EINVAL;
+
+	options = tmp = kstrdup(wmi_priv.enumeration_data[instance_id].possible_values,
+				 GFP_KERNEL);
+	if (!options)
+		return -ENOMEM;
+
+	while ((p = strsep(&options, ";")) != NULL) {
+		if (!*p)
+			continue;
+		if (!strcasecmp(p, buf)) {
+			ret = 0;
+			break;
+		}
+	}
+
+	kfree(tmp);
+	return ret;
+}
+
+attribute_s_property_show(display_name_language_code, enumeration);
+static struct kobj_attribute displ_langcode =
+		__ATTR_RO(display_name_language_code);
+
+attribute_s_property_show(display_name, enumeration);
+static struct kobj_attribute displ_name =
+		__ATTR_RO(display_name);
+
+attribute_s_property_show(default_value, enumeration);
+static struct kobj_attribute default_val =
+		__ATTR_RO(default_value);
+
+attribute_property_store(current_value, enumeration);
+static struct kobj_attribute current_val =
+		__ATTR_RW_MODE(current_value, 0600);
+
+attribute_s_property_show(dell_modifier, enumeration);
+static struct kobj_attribute modifier =
+		__ATTR_RO(dell_modifier);
+
+attribute_s_property_show(dell_value_modifier, enumeration);
+static struct kobj_attribute value_modfr =
+		__ATTR_RO(dell_value_modifier);
+
+attribute_s_property_show(possible_values, enumeration);
+static struct kobj_attribute poss_val =
+		__ATTR_RO(possible_values);
+
+static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
+{
+	return sprintf(buf, "enumeration\n");
+}
+static struct kobj_attribute type =
+		__ATTR_RO(type);
+
+static struct attribute *enumeration_attrs[] = {
+	&displ_langcode.attr,
+	&displ_name.attr,
+	&default_val.attr,
+	&current_val.attr,
+	&modifier.attr,
+	&value_modfr.attr,
+	&poss_val.attr,
+	&type.attr,
+	NULL,
+};
+
+static const struct attribute_group enumeration_attr_group = {
+	.attrs = enumeration_attrs,
+};
+
+int alloc_enum_data(void)
+{
+	int ret = 0;
+
+	wmi_priv.enumeration_instances_count =
+		get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+	wmi_priv.enumeration_data = kcalloc(wmi_priv.enumeration_instances_count,
+					sizeof(struct enumeration_data), GFP_KERNEL);
+	if (!wmi_priv.enumeration_data) {
+		wmi_priv.enumeration_instances_count = 0;
+		ret = -ENOMEM;
+	}
+	return ret;
+}
+
+/**
+ * populate_enum_data() - Populate all properties of an instance under enumeration attribute
+ * @enumeration_obj: ACPI object with enumeration data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ */
+int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
+			struct kobject *attr_name_kobj)
+{
+	int i, next_obj, value_modifier_count, possible_values_count;
+
+	wmi_priv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj;
+	strlcpy_attr(wmi_priv.enumeration_data[instance_id].attribute_name,
+		enumeration_obj[ATTR_NAME].string.pointer);
+	strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name_language_code,
+		enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
+	strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name,
+		enumeration_obj[DISPLAY_NAME].string.pointer);
+	strlcpy_attr(wmi_priv.enumeration_data[instance_id].default_value,
+		enumeration_obj[DEFAULT_VAL].string.pointer);
+	strlcpy_attr(wmi_priv.enumeration_data[instance_id].dell_modifier,
+		enumeration_obj[MODIFIER].string.pointer);
+
+	next_obj = MODIFIER + 1;
+
+	value_modifier_count = (uintptr_t)enumeration_obj[next_obj].string.pointer;
+
+	for (i = 0; i < value_modifier_count; i++) {
+		strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
+			enumeration_obj[++next_obj].string.pointer);
+		strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";");
+	}
+
+	possible_values_count = (uintptr_t) enumeration_obj[++next_obj].string.pointer;
+
+	for (i = 0; i < possible_values_count; i++) {
+		strcat(wmi_priv.enumeration_data[instance_id].possible_values,
+			enumeration_obj[++next_obj].string.pointer);
+		strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";");
+	}
+
+	return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
+}
+
+/**
+ * exit_enum_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ */
+void exit_enum_attributes(void)
+{
+	int instance_id;
+
+	for (instance_id = 0; instance_id < wmi_priv.enumeration_instances_count; instance_id++) {
+		if (wmi_priv.enumeration_data[instance_id].attr_name_kobj)
+			sysfs_remove_group(wmi_priv.enumeration_data[instance_id].attr_name_kobj,
+								&enumeration_attr_group);
+	}
+	kfree(wmi_priv.enumeration_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
new file mode 100644
index 000000000000..62cd7dbe57fe
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to integer type attributes under BIOS Integer GUID for use with
+ * dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman.h"
+
+enum int_properties {MIN_VALUE = 6, MAX_VALUE, SCALAR_INCR};
+
+get_instance_id(integer);
+
+static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int instance_id = get_integer_instance_id(kobj);
+	union acpi_object *obj;
+	ssize_t ret;
+
+	if (instance_id < 0)
+		return instance_id;
+
+	/* need to use specific instance_id and guid combination to get right data */
+	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+	if (!obj)
+		return -EIO;
+	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER)
+		return -EINVAL;
+	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[CURRENT_VAL].integer.value);
+	kfree(obj);
+	return ret;
+}
+
+/**
+ * validate_integer_input() - Validate input of current_value against lower and upper bound
+ * @instance_id: The instance on which input is validated
+ * @buf: Input value
+ */
+static int validate_integer_input(int instance_id, const char *buf)
+{
+	int in_val;
+	int ret;
+
+	ret = kstrtoint(buf, 0, &in_val);
+	if (ret)
+		return ret;
+	if (in_val < wmi_priv.integer_data[instance_id].min_value ||
+			in_val > wmi_priv.integer_data[instance_id].max_value)
+		return -EINVAL;
+
+	return ret;
+}
+
+attribute_s_property_show(display_name_language_code, integer);
+static struct kobj_attribute integer_displ_langcode =
+	__ATTR_RO(display_name_language_code);
+
+attribute_s_property_show(display_name, integer);
+static struct kobj_attribute integer_displ_name =
+	__ATTR_RO(display_name);
+
+attribute_n_property_show(default_value, integer);
+static struct kobj_attribute integer_default_val =
+	__ATTR_RO(default_value);
+
+attribute_property_store(current_value, integer);
+static struct kobj_attribute integer_current_val =
+	__ATTR_RW_MODE(current_value, 0600);
+
+attribute_s_property_show(dell_modifier, integer);
+static struct kobj_attribute integer_modifier =
+	__ATTR_RO(dell_modifier);
+
+attribute_n_property_show(min_value, integer);
+static struct kobj_attribute integer_lower_bound =
+	__ATTR_RO(min_value);
+
+attribute_n_property_show(max_value, integer);
+static struct kobj_attribute integer_upper_bound =
+	__ATTR_RO(max_value);
+
+attribute_n_property_show(scalar_increment, integer);
+static struct kobj_attribute integer_scalar_increment =
+	__ATTR_RO(scalar_increment);
+
+static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
+{
+	return sprintf(buf, "integer\n");
+}
+static struct kobj_attribute integer_type =
+	__ATTR_RO(type);
+
+static struct attribute *integer_attrs[] = {
+	&integer_displ_langcode.attr,
+	&integer_displ_name.attr,
+	&integer_default_val.attr,
+	&integer_current_val.attr,
+	&integer_modifier.attr,
+	&integer_lower_bound.attr,
+	&integer_upper_bound.attr,
+	&integer_scalar_increment.attr,
+	&integer_type.attr,
+	NULL,
+};
+
+static const struct attribute_group integer_attr_group = {
+	.attrs = integer_attrs,
+};
+
+int alloc_int_data(void)
+{
+	int ret = 0;
+
+	wmi_priv.integer_instances_count = get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+	wmi_priv.integer_data = kcalloc(wmi_priv.integer_instances_count,
+					sizeof(struct integer_data), GFP_KERNEL);
+	if (!wmi_priv.integer_data) {
+		wmi_priv.integer_instances_count = 0;
+		ret = -ENOMEM;
+	}
+	return ret;
+}
+
+/**
+ * populate_int_data() - Populate all properties of an instance under integer attribute
+ * @integer_obj: ACPI object with integer data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ */
+int populate_int_data(union acpi_object *integer_obj, int instance_id,
+			struct kobject *attr_name_kobj)
+{
+	wmi_priv.integer_data[instance_id].attr_name_kobj = attr_name_kobj;
+	strlcpy_attr(wmi_priv.integer_data[instance_id].attribute_name,
+		integer_obj[ATTR_NAME].string.pointer);
+	strlcpy_attr(wmi_priv.integer_data[instance_id].display_name_language_code,
+		integer_obj[DISPL_NAME_LANG_CODE].string.pointer);
+	strlcpy_attr(wmi_priv.integer_data[instance_id].display_name,
+		integer_obj[DISPLAY_NAME].string.pointer);
+	wmi_priv.integer_data[instance_id].default_value =
+		(uintptr_t)integer_obj[DEFAULT_VAL].string.pointer;
+	strlcpy_attr(wmi_priv.integer_data[instance_id].dell_modifier,
+		integer_obj[MODIFIER].string.pointer);
+	wmi_priv.integer_data[instance_id].min_value =
+		(uintptr_t)integer_obj[MIN_VALUE].string.pointer;
+	wmi_priv.integer_data[instance_id].max_value =
+		(uintptr_t)integer_obj[MAX_VALUE].string.pointer;
+	wmi_priv.integer_data[instance_id].scalar_increment =
+		(uintptr_t)integer_obj[SCALAR_INCR].string.pointer;
+
+	return sysfs_create_group(attr_name_kobj, &integer_attr_group);
+}
+
+/**
+ * exit_int_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ */
+void exit_int_attributes(void)
+{
+	int instance_id;
+
+	for (instance_id = 0; instance_id < wmi_priv.integer_instances_count; instance_id++) {
+		if (wmi_priv.integer_data[instance_id].attr_name_kobj)
+			sysfs_remove_group(wmi_priv.integer_data[instance_id].attr_name_kobj,
+								&integer_attr_group);
+	}
+	kfree(wmi_priv.integer_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
new file mode 100644
index 000000000000..0d11e48e2e63
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to password object type attributes under BIOS Password Object GUID for
+ * use with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman.h"
+
+enum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN};
+
+get_instance_id(po);
+
+static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr,
+					  char *buf)
+{
+	int instance_id = get_po_instance_id(kobj);
+	union acpi_object *obj;
+	ssize_t ret;
+
+	if (instance_id < 0)
+		return instance_id;
+
+	/* need to use specific instance_id and guid combination to get right data */
+	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
+	if (!obj)
+		return -EIO;
+	if (obj->package.elements[IS_PASS_SET].type != ACPI_TYPE_INTEGER)
+		return -EINVAL;
+	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[IS_PASS_SET].integer.value);
+	kfree(obj);
+	return ret;
+}
+
+struct kobj_attribute po_is_pass_set =
+		__ATTR_RO(is_enabled);
+
+static ssize_t current_password_store(struct kobject *kobj,
+				      struct kobj_attribute *attr,
+				      const char *buf, size_t count)
+{
+	char *target = NULL;
+	int length;
+
+	length = strlen(buf);
+	if (buf[length-1] == '\n')
+		length--;
+
+	/* firmware does verifiation of min/max password length,
+	 * hence only check for not exceeding MAX_BUFF here.
+	 */
+	if (length >= MAX_BUFF)
+		return -EINVAL;
+
+	if (strcmp(kobj->name, "Admin") == 0)
+		target = wmi_priv.current_admin_password;
+	else if (strcmp(kobj->name, "System") == 0)
+		target = wmi_priv.current_system_password;
+	if (!target)
+		return -EIO;
+	memcpy(target, buf, length);
+	target[length] = '\0';
+
+	return count;
+}
+
+struct kobj_attribute po_current_password =
+		__ATTR_WO(current_password);
+
+static ssize_t new_password_store(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  const char *buf, size_t count)
+{
+	char *p, *buf_cp;
+	int ret;
+
+	buf_cp = kstrdup(buf, GFP_KERNEL);
+	if (!buf_cp)
+		return -ENOMEM;
+	p = memchr(buf_cp, '\n', count);
+
+	if (p != NULL)
+		*p = '\0';
+	if (strlen(buf_cp) > MAX_BUFF) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = set_new_password(kobj->name, buf_cp);
+
+out:
+	kfree(buf_cp);
+	return ret ? ret : count;
+}
+
+struct kobj_attribute po_new_password =
+		__ATTR_WO(new_password);
+
+attribute_n_property_show(min_password_length, po);
+struct kobj_attribute po_min_pass_length =
+		__ATTR_RO(min_password_length);
+
+attribute_n_property_show(max_password_length, po);
+struct kobj_attribute po_max_pass_length =
+		__ATTR_RO(max_password_length);
+
+static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
+{
+	return sprintf(buf, "password\n");
+}
+
+struct kobj_attribute po_mechanism =
+	__ATTR_RO(mechanism);
+
+static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
+{
+	if (strcmp(kobj->name, "Admin") == 0)
+		return sprintf(buf, "bios-admin\n");
+	else if (strcmp(kobj->name, "System") == 0)
+		return sprintf(buf, "power-on\n");
+	return -EIO;
+}
+
+struct kobj_attribute po_role =
+	__ATTR_RO(role);
+
+static struct attribute *po_attrs[] = {
+	&po_is_pass_set.attr,
+	&po_min_pass_length.attr,
+	&po_max_pass_length.attr,
+	&po_current_password.attr,
+	&po_new_password.attr,
+	&po_role.attr,
+	&po_mechanism.attr,
+	NULL,
+};
+
+static const struct attribute_group po_attr_group = {
+	.attrs = po_attrs,
+};
+
+int alloc_po_data(void)
+{
+	int ret = 0;
+
+	wmi_priv.po_instances_count = get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
+	wmi_priv.po_data = kcalloc(wmi_priv.po_instances_count, sizeof(struct po_data), GFP_KERNEL);
+	if (!wmi_priv.po_data) {
+		wmi_priv.po_instances_count = 0;
+		ret = -ENOMEM;
+	}
+	return ret;
+}
+
+/**
+ * populate_po_data() - Populate all properties of an instance under password object attribute
+ * @po_obj: ACPI object with password object data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ */
+int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj)
+{
+	wmi_priv.po_data[instance_id].attr_name_kobj = attr_name_kobj;
+	strlcpy_attr(wmi_priv.po_data[instance_id].attribute_name,
+		     po_obj[ATTR_NAME].string.pointer);
+	wmi_priv.po_data[instance_id].min_password_length =
+		(uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
+	wmi_priv.po_data[instance_id].max_password_length =
+		(uintptr_t) po_obj[MAX_PASS_LEN].string.pointer;
+
+	return sysfs_create_group(attr_name_kobj, &po_attr_group);
+}
+
+/**
+ * exit_po_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ */
+void exit_po_attributes(void)
+{
+	int instance_id;
+
+	for (instance_id = 0; instance_id < wmi_priv.po_instances_count; instance_id++) {
+		if (wmi_priv.po_data[instance_id].attr_name_kobj)
+			sysfs_remove_group(wmi_priv.po_data[instance_id].attr_name_kobj,
+								&po_attr_group);
+	}
+	kfree(wmi_priv.po_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
new file mode 100644
index 000000000000..5780b4d94759
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to SET password methods under BIOS attributes interface GUID
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include <linux/wmi.h>
+#include "dell-wmi-sysman.h"
+
+static int call_password_interface(struct wmi_device *wdev, char *in_args, size_t size)
+{
+	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_buffer input;
+	union acpi_object *obj;
+	acpi_status status;
+	int ret = -EIO;
+
+	input.length =  (acpi_size) size;
+	input.pointer = in_args;
+	status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
+	if (ACPI_FAILURE(status))
+		return -EIO;
+	obj = (union acpi_object *)output.pointer;
+	if (obj->type == ACPI_TYPE_INTEGER)
+		ret = obj->integer.value;
+
+	kfree(output.pointer);
+	/* let userland know it may need to check is_password_set again */
+	kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);
+	return map_wmi_error(ret);
+}
+
+/**
+ * set_new_password() - Sets a system admin password
+ * @password_type: The type of password to set
+ * @new: The new password
+ *
+ * Sets the password using plaintext interface
+ */
+int set_new_password(const char *password_type, const char *new)
+{
+	size_t password_type_size, current_password_size, new_size;
+	size_t security_area_size, buffer_size;
+	char *buffer = NULL, *start;
+	char *current_password;
+	int ret;
+
+	mutex_lock(&wmi_priv.mutex);
+	if (!wmi_priv.password_attr_wdev) {
+		ret = -ENODEV;
+		goto out;
+	}
+	if (strcmp(password_type, "Admin") == 0) {
+		current_password = wmi_priv.current_admin_password;
+	} else if (strcmp(password_type, "System") == 0) {
+		current_password = wmi_priv.current_system_password;
+	} else {
+		ret = -EINVAL;
+		dev_err(&wmi_priv.password_attr_wdev->dev, "unknown password type %s\n",
+			password_type);
+		goto out;
+	}
+
+	/* build/calculate buffer */
+	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
+	password_type_size = calculate_string_buffer(password_type);
+	current_password_size = calculate_string_buffer(current_password);
+	new_size = calculate_string_buffer(new);
+	buffer_size = security_area_size + password_type_size + current_password_size + new_size;
+	buffer = kzalloc(buffer_size, GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/* build security area */
+	populate_security_buffer(buffer, wmi_priv.current_admin_password);
+
+	/* build variables to set */
+	start = buffer + security_area_size;
+	ret = populate_string_buffer(start, password_type_size, password_type);
+	if (ret < 0)
+		goto out;
+
+	start += ret;
+	ret = populate_string_buffer(start, current_password_size, current_password);
+	if (ret < 0)
+		goto out;
+
+	start += ret;
+	ret = populate_string_buffer(start, new_size, new);
+	if (ret < 0)
+		goto out;
+
+	print_hex_dump_bytes("set new password data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
+	ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);
+	/* clear current_password here and use user input from wmi_priv.current_password */
+	if (!ret)
+		memset(current_password, 0, MAX_BUFF);
+	/* explain to user the detailed failure reason */
+	else if (ret == -EOPNOTSUPP)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
+	else if (ret == -EACCES)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
+
+out:
+	kfree(buffer);
+	mutex_unlock(&wmi_priv.mutex);
+
+	return ret;
+}
+
+static int bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *context)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.password_attr_wdev = wdev;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static int bios_attr_pass_interface_remove(struct wmi_device *wdev)
+{
+	mutex_lock(&wmi_priv.mutex);
+	wmi_priv.password_attr_wdev = NULL;
+	mutex_unlock(&wmi_priv.mutex);
+	return 0;
+}
+
+static const struct wmi_device_id bios_attr_pass_interface_id_table[] = {
+	{ .guid_string = DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID },
+	{ },
+};
+static struct wmi_driver bios_attr_pass_interface_driver = {
+	.driver = {
+		.name = DRIVER_NAME"-password"
+	},
+	.probe = bios_attr_pass_interface_probe,
+	.remove = bios_attr_pass_interface_remove,
+	.id_table = bios_attr_pass_interface_id_table,
+};
+
+int init_bios_attr_pass_interface(void)
+{
+	return wmi_driver_register(&bios_attr_pass_interface_driver);
+}
+
+void exit_bios_attr_pass_interface(void)
+{
+	wmi_driver_unregister(&bios_attr_pass_interface_driver);
+}
+
+MODULE_DEVICE_TABLE(wmi, bios_attr_pass_interface_id_table);
diff --git a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
new file mode 100644
index 000000000000..3ff4a7f38469
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Functions corresponding to string type attributes under BIOS String GUID for use with
+ * dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#include "dell-wmi-sysman.h"
+
+enum string_properties {MIN_LEN = 6, MAX_LEN};
+
+get_instance_id(str);
+
+static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int instance_id = get_str_instance_id(kobj);
+	union acpi_object *obj;
+	ssize_t ret;
+
+	if (instance_id < 0)
+		return -EIO;
+
+	/* need to use specific instance_id and guid combination to get right data */
+	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+	if (!obj)
+		return -EIO;
+	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING)
+		return -EINVAL;
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
+	kfree(obj);
+	return ret;
+}
+
+/**
+ * validate_str_input() - Validate input of current_value against min and max lengths
+ * @instance_id: The instance on which input is validated
+ * @buf: Input value
+ */
+static int validate_str_input(int instance_id, const char *buf)
+{
+	int in_len = strlen(buf);
+
+	if ((in_len < wmi_priv.str_data[instance_id].min_length) ||
+			(in_len > wmi_priv.str_data[instance_id].max_length))
+		return -EINVAL;
+
+	return 0;
+}
+
+attribute_s_property_show(display_name_language_code, str);
+static struct kobj_attribute str_displ_langcode =
+		__ATTR_RO(display_name_language_code);
+
+attribute_s_property_show(display_name, str);
+static struct kobj_attribute str_displ_name =
+		__ATTR_RO(display_name);
+
+attribute_s_property_show(default_value, str);
+static struct kobj_attribute str_default_val =
+		__ATTR_RO(default_value);
+
+attribute_property_store(current_value, str);
+static struct kobj_attribute str_current_val =
+		__ATTR_RW_MODE(current_value, 0600);
+
+attribute_s_property_show(dell_modifier, str);
+static struct kobj_attribute str_modifier =
+		__ATTR_RO(dell_modifier);
+
+attribute_n_property_show(min_length, str);
+static struct kobj_attribute str_min_length =
+		__ATTR_RO(min_length);
+
+attribute_n_property_show(max_length, str);
+static struct kobj_attribute str_max_length =
+		__ATTR_RO(max_length);
+
+static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
+			 char *buf)
+{
+	return sprintf(buf, "string\n");
+}
+static struct kobj_attribute str_type =
+	__ATTR_RO(type);
+
+static struct attribute *str_attrs[] = {
+	&str_displ_langcode.attr,
+	&str_displ_name.attr,
+	&str_default_val.attr,
+	&str_current_val.attr,
+	&str_modifier.attr,
+	&str_min_length.attr,
+	&str_max_length.attr,
+	&str_type.attr,
+	NULL,
+};
+
+static const struct attribute_group str_attr_group = {
+	.attrs = str_attrs,
+};
+
+int alloc_str_data(void)
+{
+	int ret = 0;
+
+	wmi_priv.str_instances_count = get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+	wmi_priv.str_data = kcalloc(wmi_priv.str_instances_count,
+					sizeof(struct str_data), GFP_KERNEL);
+	if (!wmi_priv.str_data) {
+		wmi_priv.str_instances_count = 0;
+		ret = -ENOMEM;
+	}
+	return ret;
+}
+
+/**
+ * populate_str_data() - Populate all properties of an instance under string attribute
+ * @str_obj: ACPI object with integer data
+ * @instance_id: The instance to enumerate
+ * @attr_name_kobj: The parent kernel object
+ */
+int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj)
+{
+	wmi_priv.str_data[instance_id].attr_name_kobj = attr_name_kobj;
+	strlcpy_attr(wmi_priv.str_data[instance_id].attribute_name,
+		     str_obj[ATTR_NAME].string.pointer);
+	strlcpy_attr(wmi_priv.str_data[instance_id].display_name_language_code,
+		     str_obj[DISPL_NAME_LANG_CODE].string.pointer);
+	strlcpy_attr(wmi_priv.str_data[instance_id].display_name,
+		     str_obj[DISPLAY_NAME].string.pointer);
+	strlcpy_attr(wmi_priv.str_data[instance_id].default_value,
+		     str_obj[DEFAULT_VAL].string.pointer);
+	strlcpy_attr(wmi_priv.str_data[instance_id].dell_modifier,
+		     str_obj[MODIFIER].string.pointer);
+	wmi_priv.str_data[instance_id].min_length = (uintptr_t)str_obj[MIN_LEN].string.pointer;
+	wmi_priv.str_data[instance_id].max_length = (uintptr_t) str_obj[MAX_LEN].string.pointer;
+
+	return sysfs_create_group(attr_name_kobj, &str_attr_group);
+}
+
+/**
+ * exit_str_attributes() - Clear all attribute data
+ *
+ * Clears all data allocated for this group of attributes
+ */
+void exit_str_attributes(void)
+{
+	int instance_id;
+
+	for (instance_id = 0; instance_id < wmi_priv.str_instances_count; instance_id++) {
+		if (wmi_priv.str_data[instance_id].attr_name_kobj)
+			sysfs_remove_group(wmi_priv.str_data[instance_id].attr_name_kobj,
+								&str_attr_group);
+	}
+	kfree(wmi_priv.str_data);
+}
diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c
new file mode 100644
index 000000000000..3842575a6c18
--- /dev/null
+++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common methods for use with dell-wmi-sysman
+ *
+ *  Copyright (c) 2020 Dell Inc.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/fs.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/wmi.h>
+#include "dell-wmi-sysman.h"
+
+#define MAX_TYPES  4
+#include <linux/nls.h>
+
+static struct class firmware_attributes_class = {
+	.name = "firmware-attributes",
+};
+
+struct wmi_sysman_priv wmi_priv = {
+	.mutex = __MUTEX_INITIALIZER(wmi_priv.mutex),
+};
+
+/* reset bios to defaults */
+static const char * const reset_types[] = {"builtinsafe", "lastknowngood", "factory", "custom"};
+static int reset_option = -1;
+
+
+/**
+ * populate_string_buffer() - populates a string buffer
+ * @buffer: the start of the destination buffer
+ * @buffer_len: length of the destination buffer
+ * @str: the string to insert into buffer
+ */
+ssize_t populate_string_buffer(char *buffer, size_t buffer_len, const char *str)
+{
+	u16 *length = (u16 *)buffer;
+	u16 *target = length + 1;
+	int ret;
+
+	ret = utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN,
+			      target, buffer_len - sizeof(u16));
+	if (ret < 0) {
+		dev_err(wmi_priv.class_dev, "UTF16 conversion failed\n");
+		return ret;
+	}
+
+	if ((ret * sizeof(u16)) > U16_MAX) {
+		dev_err(wmi_priv.class_dev, "Error string too long\n");
+		return -ERANGE;
+	}
+
+	*length = ret * sizeof(u16);
+	return sizeof(u16) + *length;
+}
+
+/**
+ * calculate_string_buffer() - determines size of string buffer for use with BIOS communication
+ * @str: the string to calculate based upon
+ *
+ */
+size_t calculate_string_buffer(const char *str)
+{
+	/* u16 length field + one UTF16 char for each input char */
+	return sizeof(u16) + strlen(str) * sizeof(u16);
+}
+
+/**
+ * calculate_security_buffer() - determines size of security buffer for authentication scheme
+ * @authentication: the authentication content
+ *
+ * Currently only supported type is Admin password
+ */
+size_t calculate_security_buffer(char *authentication)
+{
+	if (strlen(authentication) > 0) {
+		return (sizeof(u32) * 2) + strlen(authentication) +
+			strlen(authentication) % 2;
+	}
+	return sizeof(u32) * 2;
+}
+
+/**
+ * populate_security_buffer() - builds a security buffer for authentication scheme
+ * @buffer: the buffer to populate
+ * @authentication: the authentication content
+ *
+ * Currently only supported type is PLAIN TEXT
+ */
+void populate_security_buffer(char *buffer, char *authentication)
+{
+	char *auth = buffer + sizeof(u32) * 2;
+	u32 *sectype = (u32 *) buffer;
+	u32 *seclen = sectype + 1;
+
+	*sectype = strlen(authentication) > 0 ? 1 : 0;
+	*seclen = strlen(authentication);
+
+	/* plain text */
+	if (strlen(authentication) > 0)
+		memcpy(auth, authentication, *seclen);
+}
+
+/**
+ * map_wmi_error() - map errors from WMI methods to kernel error codes
+ * @error_code: integer error code returned from Dell's firmware
+ */
+int map_wmi_error(int error_code)
+{
+	switch (error_code) {
+	case 0:
+		/* success */
+		return 0;
+	case 1:
+		/* failed */
+		return -EIO;
+	case 2:
+		/* invalid parameter */
+		return -EINVAL;
+	case 3:
+		/* access denied */
+		return -EACCES;
+	case 4:
+		/* not supported */
+		return -EOPNOTSUPP;
+	case 5:
+		/* memory error */
+		return -ENOMEM;
+	case 6:
+		/* protocol error */
+		return -EPROTO;
+	}
+	/* unspecified error */
+	return -EIO;
+}
+
+/**
+ * reset_bios_show() - sysfs implementaton for read reset_bios
+ * @kobj: Kernel object for this attribute
+ * @attr: Kernel object attribute
+ * @buf: The buffer to display to userspace
+ */
+static ssize_t reset_bios_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	char *start = buf;
+	int i;
+
+	for (i = 0; i < MAX_TYPES; i++) {
+		if (i == reset_option)
+			buf += sprintf(buf, "[%s] ", reset_types[i]);
+		else
+			buf += sprintf(buf, "%s ", reset_types[i]);
+	}
+	buf += sprintf(buf, "\n");
+	return buf-start;
+}
+
+/**
+ * reset_bios_store() - sysfs implementaton for write reset_bios
+ * @kobj: Kernel object for this attribute
+ * @attr: Kernel object attribute
+ * @buf: The buffer from userspace
+ * @count: the size of the buffer from userspace
+ */
+static ssize_t reset_bios_store(struct kobject *kobj,
+				struct kobj_attribute *attr, const char *buf, size_t count)
+{
+	int type = sysfs_match_string(reset_types, buf);
+	int ret;
+
+	if (type < 0)
+		return type;
+
+	ret = set_bios_defaults(type);
+	pr_debug("reset all attributes request type %d: %d\n", type, ret);
+	if (!ret) {
+		reset_option = type;
+		ret = count;
+	}
+
+	return ret;
+}
+
+/**
+ * pending_reboot_show() - sysfs implementaton for read pending_reboot
+ * @kobj: Kernel object for this attribute
+ * @attr: Kernel object attribute
+ * @buf: The buffer to display to userspace
+ *
+ * Stores default value as 0
+ * When current_value is changed this attribute is set to 1 to notify reboot may be required
+ */
+static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr,
+				   char *buf)
+{
+	return sprintf(buf, "%d\n", wmi_priv.pending_changes);
+}
+
+static struct kobj_attribute reset_bios = __ATTR_RW(reset_bios);
+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
+
+
+/**
+ * create_attributes_level_sysfs_files() - Creates reset_bios and
+ * pending_reboot attributes
+ */
+static int create_attributes_level_sysfs_files(void)
+{
+	int ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
+
+	if (ret) {
+		pr_debug("could not create reset_bios file\n");
+		return ret;
+	}
+
+	ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
+	if (ret) {
+		pr_debug("could not create changing_pending_reboot file\n");
+		sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
+	}
+	return ret;
+}
+
+static void release_reset_bios_data(void)
+{
+	sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
+	sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
+}
+
+static ssize_t wmi_sysman_attr_show(struct kobject *kobj, struct attribute *attr,
+				    char *buf)
+{
+	struct kobj_attribute *kattr;
+	ssize_t ret = -EIO;
+
+	kattr = container_of(attr, struct kobj_attribute, attr);
+	if (kattr->show)
+		ret = kattr->show(kobj, kattr, buf);
+	return ret;
+}
+
+static ssize_t wmi_sysman_attr_store(struct kobject *kobj, struct attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct kobj_attribute *kattr;
+	ssize_t ret = -EIO;
+
+	kattr = container_of(attr, struct kobj_attribute, attr);
+	if (kattr->store)
+		ret = kattr->store(kobj, kattr, buf, count);
+	return ret;
+}
+
+const struct sysfs_ops wmi_sysman_kobj_sysfs_ops = {
+	.show	= wmi_sysman_attr_show,
+	.store	= wmi_sysman_attr_store,
+};
+
+static void attr_name_release(struct kobject *kobj)
+{
+	kfree(kobj);
+}
+
+static struct kobj_type attr_name_ktype = {
+	.release	= attr_name_release,
+	.sysfs_ops	= &wmi_sysman_kobj_sysfs_ops,
+};
+
+/**
+ * strlcpy_attr - Copy a length-limited, NULL-terminated string with bound checks
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ */
+void strlcpy_attr(char *dest, char *src)
+{
+	size_t len = strlen(src) + 1;
+
+	if (len > 1 && len <= MAX_BUFF)
+		strlcpy(dest, src, len);
+
+	/*len can be zero because any property not-applicable to attribute can
+	 * be empty so check only for too long buffers and log error
+	 */
+	if (len > MAX_BUFF)
+		pr_err("Source string returned from BIOS is out of bound!\n");
+}
+
+/**
+ * get_wmiobj_pointer() - Get Content of WMI block for particular instance
+ * @instance_id: WMI instance ID
+ * @guid_string: WMI GUID (in str form)
+ *
+ * Fetches the content for WMI block (instance_id) under GUID (guid_string)
+ * Caller must kfree the return
+ */
+union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string)
+{
+	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
+	acpi_status status;
+
+	status = wmi_query_block(guid_string, instance_id, &out);
+
+	return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
+}
+
+/**
+ * get_instance_count() - Compute total number of instances under guid_string
+ * @guid_string: WMI GUID (in string form)
+ */
+int get_instance_count(const char *guid_string)
+{
+	union acpi_object *wmi_obj = NULL;
+	int i = 0;
+
+	do {
+		kfree(wmi_obj);
+		wmi_obj = get_wmiobj_pointer(i, guid_string);
+		i++;
+	} while (wmi_obj);
+
+	return (i-1);
+}
+
+/**
+ * alloc_attributes_data() - Allocate attributes data for a particular type
+ * @attr_type: Attribute type to allocate
+ */
+static int alloc_attributes_data(int attr_type)
+{
+	int retval = 0;
+
+	switch (attr_type) {
+	case ENUM:
+		retval = alloc_enum_data();
+		break;
+	case INT:
+		retval = alloc_int_data();
+		break;
+	case STR:
+		retval = alloc_str_data();
+		break;
+	case PO:
+		retval = alloc_po_data();
+		break;
+	default:
+		break;
+	}
+
+	return retval;
+}
+
+/**
+ * destroy_attribute_objs() - Free a kset of kobjects
+ * @kset: The kset to destroy
+ *
+ * Fress kobjects created for each attribute_name under attribute type kset
+ */
+static void destroy_attribute_objs(struct kset *kset)
+{
+	struct kobject *pos, *next;
+
+	list_for_each_entry_safe(pos, next, &kset->list, entry) {
+		kobject_put(pos);
+	}
+}
+
+/**
+ * release_attributes_data() - Clean-up all sysfs directories and files created
+ */
+static void release_attributes_data(void)
+{
+	release_reset_bios_data();
+
+	mutex_lock(&wmi_priv.mutex);
+	exit_enum_attributes();
+	exit_int_attributes();
+	exit_str_attributes();
+	exit_po_attributes();
+	if (wmi_priv.authentication_dir_kset) {
+		destroy_attribute_objs(wmi_priv.authentication_dir_kset);
+		kset_unregister(wmi_priv.authentication_dir_kset);
+		wmi_priv.authentication_dir_kset = NULL;
+	}
+	if (wmi_priv.main_dir_kset) {
+		destroy_attribute_objs(wmi_priv.main_dir_kset);
+		kset_unregister(wmi_priv.main_dir_kset);
+	}
+	mutex_unlock(&wmi_priv.mutex);
+
+}
+
+/**
+ * init_bios_attributes() - Initialize all attributes for a type
+ * @attr_type: The attribute type to initialize
+ * @guid: The WMI GUID associated with this type to initialize
+ *
+ * Initialiaze all 4 types of attributes enumeration, integer, string and password object.
+ * Populates each attrbute typ's respective properties under sysfs files
+ */
+static int init_bios_attributes(int attr_type, const char *guid)
+{
+	struct kobject *attr_name_kobj; //individual attribute names
+	union acpi_object *obj = NULL;
+	union acpi_object *elements;
+	struct kset *tmp_set;
+
+	/* instance_id needs to be reset for each type GUID
+	 * also, instance IDs are unique within GUID but not across
+	 */
+	int instance_id = 0;
+	int retval = 0;
+
+	retval = alloc_attributes_data(attr_type);
+	if (retval)
+		return retval;
+	/* need to use specific instance_id and guid combination to get right data */
+	obj = get_wmiobj_pointer(instance_id, guid);
+	if (!obj)
+		return -ENODEV;
+	elements = obj->package.elements;
+
+	mutex_lock(&wmi_priv.mutex);
+	while (elements) {
+		/* sanity checking */
+		if (strlen(elements[ATTR_NAME].string.pointer) == 0) {
+			pr_debug("empty attribute found\n");
+			goto nextobj;
+		}
+		if (attr_type == PO)
+			tmp_set = wmi_priv.authentication_dir_kset;
+		else
+			tmp_set = wmi_priv.main_dir_kset;
+
+		if (kset_find_obj(tmp_set, elements[ATTR_NAME].string.pointer)) {
+			pr_debug("duplicate attribute name found - %s\n",
+				elements[ATTR_NAME].string.pointer);
+			goto nextobj;
+		}
+
+		/* build attribute */
+		attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
+		if (!attr_name_kobj)
+			goto err_attr_init;
+
+		attr_name_kobj->kset = tmp_set;
+
+		retval = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, NULL, "%s",
+						elements[ATTR_NAME].string.pointer);
+		if (retval) {
+			kobject_put(attr_name_kobj);
+			goto err_attr_init;
+		}
+
+		/* enumerate all of this attribute */
+		switch (attr_type) {
+		case ENUM:
+			retval = populate_enum_data(elements, instance_id, attr_name_kobj);
+			break;
+		case INT:
+			retval = populate_int_data(elements, instance_id, attr_name_kobj);
+			break;
+		case STR:
+			retval = populate_str_data(elements, instance_id, attr_name_kobj);
+			break;
+		case PO:
+			retval = populate_po_data(elements, instance_id, attr_name_kobj);
+			break;
+		default:
+			break;
+		}
+
+		if (retval) {
+			pr_debug("failed to populate %s\n",
+				elements[ATTR_NAME].string.pointer);
+			goto err_attr_init;
+		}
+
+nextobj:
+		kfree(obj);
+		instance_id++;
+		obj = get_wmiobj_pointer(instance_id, guid);
+		elements = obj ? obj->package.elements : NULL;
+	}
+
+	goto out;
+
+err_attr_init:
+	release_attributes_data();
+	kfree(obj);
+out:
+	mutex_unlock(&wmi_priv.mutex);
+	return retval;
+}
+
+static int __init sysman_init(void)
+{
+	int ret = 0;
+
+	if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) &&
+	    !dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) {
+		pr_err("Unable to run on non-Dell system\n");
+		return -ENODEV;
+	}
+
+	ret = init_bios_attr_set_interface();
+	if (ret || !wmi_priv.bios_attr_wdev) {
+		pr_debug("failed to initialize set interface\n");
+		goto fail_set_interface;
+	}
+
+	ret = init_bios_attr_pass_interface();
+	if (ret || !wmi_priv.password_attr_wdev) {
+		pr_debug("failed to initialize pass interface\n");
+		goto fail_pass_interface;
+	}
+
+	ret = class_register(&firmware_attributes_class);
+	if (ret)
+		goto fail_class;
+
+	wmi_priv.class_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0),
+				  NULL, "%s", DRIVER_NAME);
+	if (IS_ERR(wmi_priv.class_dev)) {
+		ret = PTR_ERR(wmi_priv.class_dev);
+		goto fail_classdev;
+	}
+
+	wmi_priv.main_dir_kset = kset_create_and_add("attributes", NULL,
+						     &wmi_priv.class_dev->kobj);
+	if (!wmi_priv.main_dir_kset) {
+		ret = -ENOMEM;
+		goto fail_main_kset;
+	}
+
+	wmi_priv.authentication_dir_kset = kset_create_and_add("authentication", NULL,
+								&wmi_priv.class_dev->kobj);
+	if (!wmi_priv.authentication_dir_kset) {
+		ret = -ENOMEM;
+		goto fail_authentication_kset;
+	}
+
+	ret = create_attributes_level_sysfs_files();
+	if (ret) {
+		pr_debug("could not create reset BIOS attribute\n");
+		goto fail_reset_bios;
+	}
+
+	ret = init_bios_attributes(ENUM, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+	if (ret) {
+		pr_debug("failed to populate enumeration type attributes\n");
+		goto fail_create_group;
+	}
+
+	ret = init_bios_attributes(INT, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+	if (ret) {
+		pr_debug("failed to populate integer type attributes\n");
+		goto fail_create_group;
+	}
+
+	ret = init_bios_attributes(STR, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+	if (ret) {
+		pr_debug("failed to populate string type attributes\n");
+		goto fail_create_group;
+	}
+
+	ret = init_bios_attributes(PO, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
+	if (ret) {
+		pr_debug("failed to populate pass object type attributes\n");
+		goto fail_create_group;
+	}
+
+	return 0;
+
+fail_create_group:
+	release_attributes_data();
+
+fail_reset_bios:
+	if (wmi_priv.authentication_dir_kset) {
+		kset_unregister(wmi_priv.authentication_dir_kset);
+		wmi_priv.authentication_dir_kset = NULL;
+	}
+
+fail_authentication_kset:
+	if (wmi_priv.main_dir_kset) {
+		kset_unregister(wmi_priv.main_dir_kset);
+		wmi_priv.main_dir_kset = NULL;
+	}
+
+fail_main_kset:
+	device_destroy(&firmware_attributes_class, MKDEV(0, 0));
+
+fail_classdev:
+	class_unregister(&firmware_attributes_class);
+
+fail_class:
+	exit_bios_attr_pass_interface();
+
+fail_pass_interface:
+	exit_bios_attr_set_interface();
+
+fail_set_interface:
+	return ret;
+}
+
+static void __exit sysman_exit(void)
+{
+	release_attributes_data();
+	device_destroy(&firmware_attributes_class, MKDEV(0, 0));
+	class_unregister(&firmware_attributes_class);
+	exit_bios_attr_set_interface();
+	exit_bios_attr_pass_interface();
+}
+
+module_init(sysman_init);
+module_exit(sysman_exit);
+
+MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
+MODULE_AUTHOR("Prasanth Ksr <prasanth.ksr@dell.com>");
+MODULE_AUTHOR("Divya Bharathi <divya.bharathi@dell.com>");
+MODULE_DESCRIPTION("Dell platform setting control interface");
+MODULE_LICENSE("GPL");
-- 
2.25.1


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

* Re: [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-10-27 13:49 [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems Divya Bharathi
@ 2020-10-28  9:57 ` Hans de Goede
  2020-10-29  8:01 ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 6+ messages in thread
From: Hans de Goede @ 2020-10-28  9:57 UTC (permalink / raw)
  To: Divya Bharathi, dvhart
  Cc: LKML, platform-driver-x86, Divya Bharathi, Andy Shevchenko,
	mark gross, Mario Limonciello, Prasanth KSR

Hi,

On 10/27/20 2:49 PM, Divya Bharathi wrote:
> The Dell WMI Systems Management Driver provides a sysfs
> interface for systems management to enable BIOS configuration
> capability on certain Dell Systems.
> 
> This driver allows user to configure Dell systems with a
> uniform common interface. To facilitate this, the patch
> introduces a generic way for driver to be able to create
> configurable BIOS Attributes available in Setup (F2) screen.
> 
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
> Cc: mark gross <mgross@linux.intel.com>
> 
> Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> Co-developed-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Divya Bharathi <divya.bharathi@dell.com>

Thank you for your patch, I've applied this patch to my review-hans 
branch:
https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans

Note I've made 2 small changes while applying this:

1. I've added a missing "This attribute is mandatory." to the docs for
the /sys/class/firmware-attributes/*/authentication/*/is_enabled
sysfs file.

2. You did a direct return after the ACPI object type check, in
the various current_value_show functions:

       if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING)
               return -EINVAL;

This leaks the object returned by get_wmiobj_pointer() I've added the
missing kfree() call like this:

--- a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
+++ b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
@@ -23,8 +23,10 @@ static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *a
 	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
 	if (!obj)
 		return -EIO;
-	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING)
+	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
+		kfree(obj);
 		return -EINVAL;
+	}
 	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
 	kfree(obj);
 	return ret;

And I did the same for all the other cases.

Once I've run some tests on my review-hans branch the patches there will
be added to the platform-drivers-x86/for-next branch and eventually
will be included in the pdx86 pull-request to Linus for the next
merge-window.

Regards,

Hans


> ---
> 
> Changes from v6 to v7:
>  - Set current_value to rw only for root user
>  - Correct spacing in sysfs documentation
>  - Make some more attributes mandatory
>  - Remove cap_sys_admin check
>  - add extra check for -ENOMEM for attribute_property_store
>  - Add dereferencing check for data types read
>  - Adjust passobj bounds check by 1
>  - Add extra check for -ENOMEM in new_password_store
>  - Clear current password properly
>  - Simplify reset_bios_store
>  - Adjust helper functions per Hans' suggestions
>  - Correct integer handling abusing ACPI core
> 
> Changes from v5 to v6:
>  - Fixed Mutex bug in set_bios_defaults
>  - Adjust wrapping for enum-attributes.c description
>  - Adjust wrapping for int-attributes.c comparison
>  - Make current_password mandatory for mechanism == password
>  - Move strlen of admin check into populate_security_password
>  - Use correct device for dev_err calls (bios_attr_wdev)
>  - Remove type from structs and add type-string directly in show functions
>  - Remove unneeded macro definition (make function static)
>  - Make calls to get_*_instance_id error handling match kernel style
>  - Adjust -AE_ERROR to -EIO
>  - Adjust validate_integer_input to propagate errors
>  - Make current_password_store return -EIO for an unknown type
>  - Don't store current_value, read dynamically every time
>  - Move kobject_uevents to class_dev
>  - Update all kernel doc comments with standard termination '*/'
>  - Correct dereferences in alloc_*_data()
>  - Make value_modifier and value_modifier_count local
>  - Remove is_enabled from po
>  - Fix current_password_store const char* handling
>  - Propagate error value from get_po_instance_id() in is_enabled_show()
>  - Adjust validate_str_input
>  - Cleanups to reset_bios_store to use sysfs_match_string
>  - Adjust set_bios_defaults
>  - Rename create_reset_bios
>  - strlcpy_attr handling
>  - Check number of kset_unregister calls in error path
>  - Make teardown order match error order
>  - Pass password into calculate_security_buffer
>  - Correct handling of const char * values in macros
>  - Add new function for populating string buffers
>  - Switch strncasecmp to strcasecmp
>    + This wasn't strictly necessary (the firmware rejected invalid strings)
>    + However, by doing it in the kernel we can send a more sensbile error -EINVAL
> 
> Changes from v4 to v5:
>  - Correct Kconfig description to not use "WMI" twice.
>  - s/is_authentication_set/is_enabled/
>  - Specify that all attributes are optional and take UTF8
>  - Change authentication type to "role" and "mechanism"
>  - Explain what semicolons are
>  - Adjust whitespace of documentation
> 
> Changes from v3 to v4:
>  - Create a firmware-attributes class and tie ksets to a virtual device in it
>  - Make modifier and value_modifier "dell only" attributes.
>  - Correct some errors caught by kernel build bot around missing prototypes
>  - Remove mutexes from populate_* functions and put in init_dell_bios_attrib_wmi instead
>  - Move all code into a subdirectory drivers/platform/x86/dell-wmi-sysman and remove dell-wmi-*
>    prefix on files
>  - Move all data structures into shared struct
>  - In alloc functions instead of kzalloc use kcalloc and check that there is no overflow
>    + Same check for other alloc_foo-data functions
>  -  populate_*: Move sysfs_create_group to end of the function to prevent race conditions
>  - Save kernel object into each data instance and only remove that rather than sysfs_remove_group
>  - Document in sysfs file what causes change uevents to come through
>  - Only notify with change uevent one time on multiple settings modifications
>  - Adjust lots of string handling
>  - Make more objects static
>  - Various whitespace corrections
>  - Document map_wmi_error properly
>  - Bump version to 5.11 (February 2021)
> 
> Changes from v2 to v3:
>  - Fix a possible NULL pointer error in init
>  - Add missing newlines to all dev_err/dev_dbg/pr_err/pr_debug statements
>  - Correct updating passwords when both Admin and System password are set
>  - Correct the WMI driver name
>  - Correct some namespace clashing when compiled into the kernel (Reported by Mark Gross)
>  - Correct some comment typos
>  - Adopt suggestions made by Hans:
>    + Use single global mutex
>    + Clarify reason for uevents with a comment
>    + Remove functions for set and get current password
>    + Rename lower_bound to min_value and upper_bound to max_value
>    + Rename possible_value to possible_values
>    + Remove references to float
>    + Build a separate passwords directory again since it behaves differently from the other
>      attributes
>    + Move more calls from pr_err -> dev_err
>  - Documentation cleanups (see v2 patch feedback)
>    + Grouping types
>    + Syntax of `modifier` output
> 
> Changes from v1 to v2:
>  - use pr_fmt instead of pr_err(DRIVER_NAME
>  - re-order variables reverse xmas tree order
>  - correct returns of -1 to error codes
>  - correct usage of {} on some split line statements
>  - Refine all documentation deficiencies suggested by Hans
>  - Merge all attributes to a single directory
>  - Overhaul WMI interface interaction as suggested by Hans
>    * Move WMI driver registration to start of module
>    * Remove usage of lists that only use first entry for WMI interfaces
>    * Create a global structure shared across interface source files
>    * Make get_current_password function static
>    * Remove get_pending changes function, shared across global structure now.
>  - Overhaul use of mutexes
>    * Make kset list mutex shared across source files
>    * Remove unneeded dell-wmi-sysman call_mutex
>    * Keep remaining call_mutexes in WMI functions
>  - Move security area calculation into a function
>  - Use NLS helper for utf8->utf16 conversion
> 
>  .../testing/sysfs-class-firmware-attributes   | 223 +++++++
>  MAINTAINERS                                   |   8 +
>  drivers/platform/x86/Kconfig                  |  12 +
>  drivers/platform/x86/Makefile                 |   1 +
>  drivers/platform/x86/dell-wmi-sysman/Makefile |   8 +
>  .../x86/dell-wmi-sysman/biosattr-interface.c  | 186 ++++++
>  .../x86/dell-wmi-sysman/dell-wmi-sysman.h     | 191 ++++++
>  .../x86/dell-wmi-sysman/enum-attributes.c     | 187 ++++++
>  .../x86/dell-wmi-sysman/int-attributes.c      | 171 +++++
>  .../x86/dell-wmi-sysman/passobj-attributes.c  | 192 ++++++
>  .../dell-wmi-sysman/passwordattr-interface.c  | 153 +++++
>  .../x86/dell-wmi-sysman/string-attributes.c   | 157 +++++
>  drivers/platform/x86/dell-wmi-sysman/sysman.c | 625 ++++++++++++++++++
>  13 files changed, 2114 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-firmware-attributes
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/Makefile
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>  create mode 100644 drivers/platform/x86/dell-wmi-sysman/sysman.c
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> new file mode 100644
> index 000000000000..feee3b860e5a
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> @@ -0,0 +1,223 @@
> +What:		/sys/class/firmware-attributes/*/attributes/*/
> +Date:		February 2021
> +KernelVersion:	5.11
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +Description:
> +		A sysfs interface for systems management software to enable
> +		configuration capability on supported systems.  This directory
> +		exposes interfaces for interacting with configuration options.
> +
> +		Unless otherwise specified in an attribute description all attributes are optional
> +		and will accept UTF-8 input.
> +
> +		type: A file that can be read to obtain the type of attribute.  This attribute is
> +			mandatory.
> +
> +		The following are known types:
> +			- enumeration: a set of pre-defined valid values
> +			- integer: a range of numerical values
> +			- string
> +
> +		All attribute types support the following values:
> +
> +		current_value:	A file that can be read to obtain the current
> +				value of the <attr>.
> +
> +				This file can also be written to in order to update the value of a
> +				<attr>
> +
> +				This attribute is mandatory.
> +
> +		default_value:	A file that can be read to obtain the default
> +				value of the <attr>
> +
> +		display_name:	A file that can be read to obtain a user friendly
> +				description of the at <attr>
> +
> +		display_name_language_code:	A file that can be read to obtain
> +						the IETF language tag corresponding to the
> +						"display_name" of the <attr>
> +
> +		"enumeration"-type specific properties:
> +
> +		possible_values:	A file that can be read to obtain the possible
> +					values of the <attr>. Values are separated using
> +					semi-colon (``;``).
> +
> +		"integer"-type specific properties:
> +
> +		min_value:	A file that can be read to obtain the lower
> +				bound value of the <attr>
> +
> +		max_value:	A file that can be read to obtain the upper
> +				bound value of the <attr>
> +
> +		scalar_increment:	A file that can be read to obtain the scalar value used for
> +					increments of current_value this attribute accepts.
> +
> +		"string"-type specific properties:
> +
> +		max_length:	A file that can be read to obtain the maximum
> +				length value of the <attr>
> +
> +		min_length:	A file that can be read to obtain the minimum
> +				length value of the <attr>
> +
> +		Dell specific class extensions
> +		--------------------------
> +
> +		On Dell systems the following additional attributes are available:
> +
> +		dell_modifier:	A file that can be read to obtain attribute-level
> +				dependency rule. It says an attribute X will become read-only or
> +				suppressed, if/if-not attribute Y is configured.
> +
> +				modifier rules can be in following format:
> +				[ReadOnlyIf:<attribute>=<value>]
> +				[ReadOnlyIfNot:<attribute>=<value>]
> +				[SuppressIf:<attribute>=<value>]
> +				[SuppressIfNot:<attribute>=<value>]
> +
> +				For example:
> +				AutoOnFri/dell_modifier has value,
> +					[SuppressIfNot:AutoOn=SelectDays]
> +
> +				This means AutoOnFri will be suppressed in BIOS setup if AutoOn
> +				attribute is not "SelectDays" and its value will not be effective
> +				through sysfs until this rule is met.
> +
> +		Enumeration attributes also support the following:
> +
> +		dell_value_modifier:	A file that can be read to obtain value-level dependency.
> +					This file is similar to dell_modifier but here,	an
> +					attribute's current value will be forcefully changed based
> +					dependent attributes value.
> +
> +					dell_value_modifier rules can be in following format:
> +					<value>[ForceIf:<attribute>=<value>]
> +					<value>[ForceIfNot:<attribute>=<value>]
> +
> +					For example,
> +					LegacyOrom/dell_value_modifier has value:
> +						Disabled[ForceIf:SecureBoot=Enabled]
> +					This means LegacyOrom's current value will be forced to
> +					"Disabled" in BIOS setup if SecureBoot is Enabled and its
> +					value will not be effective through sysfs until this rule is
> +					met.
> +
> +What:		/sys/class/firmware-attributes/*/authentication/
> +Date:		February 2021
> +KernelVersion:	5.11
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +
> +		Devices support various authentication mechanisms which can be exposed
> +		as a separate configuration object.
> +
> +		For example a "BIOS Admin" password and "System" Password can be set,
> +		reset or cleared using these attributes.
> +		- An "Admin" password is used for preventing modification to the BIOS
> +		  settings.
> +		- A "System" password is required to boot a machine.
> +
> +		Change in any of these two authentication methods will also generate an
> +		uevent KOBJ_CHANGE.
> +
> +		is_enabled:		A file that can be read to obtain a 0/1 flag to see if
> +					<attr> authentication is enabled.
> +
> +		role:			The type of authentication used.
> +					This attribute is mandatory.
> +					Known types:
> +						bios-admin: Representing BIOS administrator password
> +						power-on: Representing a password required to use
> +							  the system
> +
> +		mechanism:		The means of authentication.  This attribute is mandatory.
> +					Only supported type currently is "password".
> +
> +		max_password_length:	A file that can be read to obtain the
> +					maximum length of the Password
> +
> +		min_password_length:	A file that can be read to obtain the
> +					minimum length of the Password
> +
> +		current_password:	A write only value used for privileged access such as
> +					setting	attributes when a system or admin password is set
> +					or resetting to a new password
> +
> +					This attribute is mandatory when mechanism == "password".
> +
> +		new_password:		A write only value that when used in tandem with
> +					current_password will reset a system or admin password.
> +
> +		Note, password management is session specific. If Admin password is set,
> +		same password must be written into current_password file (required for
> +		password-validation) and must be cleared once the session is over.
> +		For example:
> +			echo "password" > current_password
> +			echo "disabled" > TouchScreen/current_value
> +			echo "" > current_password
> +
> +		Drivers may emit a CHANGE uevent when a password is set or unset
> +		userspace may check it again.
> +
> +		On Dell systems, if Admin password is set, then all BIOS attributes
> +		require password validation.
> +
> +What:		/sys/class/firmware-attributes/*/attributes/pending_reboot
> +Date:		February 2021
> +KernelVersion:	5.11
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +Description:
> +		A read-only attribute reads 1 if a reboot is necessary to apply
> +		pending BIOS attribute changes. Also, an uevent_KOBJ_CHANGE is
> +		generated when it changes to 1.
> +
> +			0:	All BIOS attributes setting are current
> +			1:	A reboot is necessary to get pending BIOS attribute changes
> +				applied
> +
> +		Note, userspace applications need to follow below steps for efficient
> +		BIOS management,
> +		1.	Check if admin password is set. If yes, follow session method for
> +			password management as briefed under authentication section above.
> +		2.	Before setting any attribute, check if it has any modifiers
> +			or value_modifiers. If yes, incorporate them and then modify
> +			attribute.
> +
> +		Drivers may emit a CHANGE uevent when this value changes and userspace
> +		may check it again.
> +
> +What:		/sys/class/firmware-attributes/*/attributes/reset_bios
> +Date:		February 2021
> +KernelVersion:	5.11
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +Description:
> +		This attribute can be used to reset the BIOS Configuration.
> +		Specifically, it tells which type of reset BIOS configuration is being
> +		requested on the host.
> +
> +		Reading from it returns a list of supported options encoded as:
> +
> +			'builtinsafe' (Built in safe configuration profile)
> +			'lastknowngood' (Last known good saved configuration profile)
> +			'factory' (Default factory settings configuration profile)
> +			'custom' (Custom saved configuration profile)
> +
> +		The currently selected option is printed in square brackets as
> +		shown below:
> +
> +		# echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
> +		# cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
> +		# builtinsafe lastknowngood [factory] custom
> +
> +		Note that any changes to this attribute requires a reboot
> +		for changes to take effect.
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e73636b75f29..e6e71444545a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4991,6 +4991,14 @@ M:	Mario Limonciello <mario.limonciello@dell.com>
>  S:	Maintained
>  F:	drivers/platform/x86/dell-wmi-descriptor.c
>  
> +DELL WMI SYSMAN DRIVER
> +M:	Divya Bharathi <divya.bharathi@dell.com>
> +M:	Mario Limonciello <mario.limonciello@dell.com>
> +M:	Prasanth Ksr <prasanth.ksr@dell.com>
> +L:	platform-driver-x86@vger.kernel.org
> +S:	Maintained
> +F:	drivers/platform/x86/dell-wmi-syman/*
> +
>  DELL WMI NOTIFICATIONS DRIVER
>  M:	Matthew Garrett <mjg59@srcf.ucam.org>
>  M:	Pali Rohár <pali@kernel.org>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 0d91d136bc3b..7b6e90546b17 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -430,6 +430,18 @@ config DELL_WMI
>  	  To compile this driver as a module, choose M here: the module will
>  	  be called dell-wmi.
>  
> +config DELL_WMI_SYSMAN
> +	tristate "Dell WMI-based Systems management driver"
> +	depends on ACPI_WMI
> +	depends on DMI
> +	select NLS
> +	help
> +	  This driver allows changing BIOS settings on many Dell machines from
> +	  2018 and newer without the use of any additional software.
> +
> +	  To compile this driver as a module, choose M here: the module will
> +	  be called dell-wmi-sysman.
> +
>  config DELL_WMI_DESCRIPTOR
>  	tristate
>  	depends on ACPI_WMI
> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
> index 5f823f7eff45..36ce38e80c8f 100644
> --- a/drivers/platform/x86/Makefile
> +++ b/drivers/platform/x86/Makefile
> @@ -47,6 +47,7 @@ obj-$(CONFIG_DELL_WMI)			+= dell-wmi.o
>  obj-$(CONFIG_DELL_WMI_DESCRIPTOR)	+= dell-wmi-descriptor.o
>  obj-$(CONFIG_DELL_WMI_AIO)		+= dell-wmi-aio.o
>  obj-$(CONFIG_DELL_WMI_LED)		+= dell-wmi-led.o
> +obj-$(CONFIG_DELL_WMI_SYSMAN)		+= dell-wmi-sysman/
>  
>  # Fujitsu
>  obj-$(CONFIG_AMILO_RFKILL)	+= amilo-rfkill.o
> diff --git a/drivers/platform/x86/dell-wmi-sysman/Makefile b/drivers/platform/x86/dell-wmi-sysman/Makefile
> new file mode 100644
> index 000000000000..825fb2fbeea8
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/Makefile
> @@ -0,0 +1,8 @@
> +obj-$(CONFIG_DELL_WMI_SYSMAN)  += dell-wmi-sysman.o
> +dell-wmi-sysman-objs := 	sysman.o		\
> +				enum-attributes.o	\
> +				int-attributes.o	\
> +				string-attributes.o	\
> +				passobj-attributes.o	\
> +				biosattr-interface.o	\
> +				passwordattr-interface.o
> diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> new file mode 100644
> index 000000000000..f95d8ddace5a
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> @@ -0,0 +1,186 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to SET methods under BIOS attributes interface GUID for use
> + * with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include <linux/wmi.h>
> +#include "dell-wmi-sysman.h"
> +
> +#define SETDEFAULTVALUES_METHOD_ID					0x02
> +#define SETBIOSDEFAULTS_METHOD_ID					0x03
> +#define SETATTRIBUTE_METHOD_ID						0x04
> +
> +static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
> +					int method_id)
> +{
> +	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
> +	struct acpi_buffer input;
> +	union acpi_object *obj;
> +	acpi_status status;
> +	int ret = -EIO;
> +
> +	input.length =  (acpi_size) size;
> +	input.pointer = in_args;
> +	status = wmidev_evaluate_method(wdev, 0, method_id, &input, &output);
> +	if (ACPI_FAILURE(status))
> +		return -EIO;
> +	obj = (union acpi_object *)output.pointer;
> +	if (obj->type == ACPI_TYPE_INTEGER)
> +		ret = obj->integer.value;
> +
> +	if (wmi_priv.pending_changes == 0) {
> +		wmi_priv.pending_changes = 1;
> +		/* let userland know it may need to check reboot pending again */
> +		kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);
> +	}
> +	kfree(output.pointer);
> +	return map_wmi_error(ret);
> +}
> +
> +/**
> + * set_attribute() - Update an attribute value
> + * @a_name: The attribute name
> + * @a_value: The attribute value
> + *
> + * Sets an attribute to new value
> + */
> +int set_attribute(const char *a_name, const char *a_value)
> +{
> +	size_t security_area_size, buffer_size;
> +	size_t a_name_size, a_value_size;
> +	char *buffer = NULL, *start;
> +	int ret;
> +
> +	mutex_lock(&wmi_priv.mutex);
> +	if (!wmi_priv.bios_attr_wdev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	/* build/calculate buffer */
> +	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
> +	a_name_size = calculate_string_buffer(a_name);
> +	a_value_size = calculate_string_buffer(a_value);
> +	buffer_size = security_area_size + a_name_size + a_value_size;
> +	buffer = kzalloc(buffer_size, GFP_KERNEL);
> +	if (!buffer) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	/* build security area */
> +	populate_security_buffer(buffer, wmi_priv.current_admin_password);
> +
> +	/* build variables to set */
> +	start = buffer + security_area_size;
> +	ret = populate_string_buffer(start, a_name_size, a_name);
> +	if (ret < 0)
> +		goto out;
> +	start += ret;
> +	ret = populate_string_buffer(start, a_value_size, a_value);
> +	if (ret < 0)
> +		goto out;
> +
> +	print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
> +	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
> +					    buffer, buffer_size,
> +					    SETATTRIBUTE_METHOD_ID);
> +	if (ret == -EOPNOTSUPP)
> +		dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n");
> +	else if (ret == -EACCES)
> +		dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
> +
> +out:
> +	kfree(buffer);
> +	mutex_unlock(&wmi_priv.mutex);
> +	return ret;
> +}
> +
> +/**
> + * set_bios_defaults() - Resets BIOS defaults
> + * @deftype: the type of BIOS value reset to issue.
> + *
> + * Resets BIOS defaults
> + */
> +int set_bios_defaults(u8 deftype)
> +{
> +	size_t security_area_size, buffer_size;
> +	size_t integer_area_size = sizeof(u8);
> +	char *buffer = NULL;
> +	u8 *defaultType;
> +	int ret;
> +
> +	mutex_lock(&wmi_priv.mutex);
> +	if (!wmi_priv.bios_attr_wdev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +
> +	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
> +	buffer_size = security_area_size + integer_area_size;
> +	buffer = kzalloc(buffer_size, GFP_KERNEL);
> +	if (!buffer) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	/* build security area */
> +	populate_security_buffer(buffer, wmi_priv.current_admin_password);
> +
> +	defaultType = buffer + security_area_size;
> +	*defaultType = deftype;
> +
> +	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
> +					    SETBIOSDEFAULTS_METHOD_ID);
> +	if (ret)
> +		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
> +
> +	kfree(buffer);
> +out:
> +	mutex_unlock(&wmi_priv.mutex);
> +	return ret;
> +}
> +
> +static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
> +{
> +	mutex_lock(&wmi_priv.mutex);
> +	wmi_priv.bios_attr_wdev = wdev;
> +	mutex_unlock(&wmi_priv.mutex);
> +	return 0;
> +}
> +
> +static int bios_attr_set_interface_remove(struct wmi_device *wdev)
> +{
> +	mutex_lock(&wmi_priv.mutex);
> +	wmi_priv.bios_attr_wdev = NULL;
> +	mutex_unlock(&wmi_priv.mutex);
> +	return 0;
> +}
> +
> +static const struct wmi_device_id bios_attr_set_interface_id_table[] = {
> +	{ .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID },
> +	{ },
> +};
> +static struct wmi_driver bios_attr_set_interface_driver = {
> +	.driver = {
> +		.name = DRIVER_NAME
> +	},
> +	.probe = bios_attr_set_interface_probe,
> +	.remove = bios_attr_set_interface_remove,
> +	.id_table = bios_attr_set_interface_id_table,
> +};
> +
> +int init_bios_attr_set_interface(void)
> +{
> +	return wmi_driver_register(&bios_attr_set_interface_driver);
> +}
> +
> +void exit_bios_attr_set_interface(void)
> +{
> +	wmi_driver_unregister(&bios_attr_set_interface_driver);
> +}
> +
> +MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
> diff --git a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
> new file mode 100644
> index 000000000000..b80f2a62ea3f
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
> @@ -0,0 +1,191 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + * Definitions for kernel modules using Dell WMI System Management Driver
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#ifndef _DELL_WMI_BIOS_ATTR_H_
> +#define _DELL_WMI_BIOS_ATTR_H_
> +
> +#include <linux/wmi.h>
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/capability.h>
> +
> +#define DRIVER_NAME					"dell-wmi-sysman"
> +#define MAX_BUFF  512
> +
> +#define DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID	"F1DDEE52-063C-4784-A11E-8A06684B9BF5"
> +#define DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BFA"
> +#define DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BF9"
> +#define DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID		"0894B8D6-44A6-4719-97D7-6AD24108BFD4"
> +#define DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID		"F1DDEE52-063C-4784-A11E-8A06684B9BF4"
> +#define DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID		"70FE8229-D03B-4214-A1C6-1F884B1A892A"
> +
> +struct enumeration_data {
> +	struct kobject *attr_name_kobj;
> +	char display_name_language_code[MAX_BUFF];
> +	char dell_value_modifier[MAX_BUFF];
> +	char possible_values[MAX_BUFF];
> +	char attribute_name[MAX_BUFF];
> +	char default_value[MAX_BUFF];
> +	char dell_modifier[MAX_BUFF];
> +	char display_name[MAX_BUFF];
> +};
> +
> +struct integer_data {
> +	struct kobject *attr_name_kobj;
> +	char display_name_language_code[MAX_BUFF];
> +	char attribute_name[MAX_BUFF];
> +	char dell_modifier[MAX_BUFF];
> +	char display_name[MAX_BUFF];
> +	int scalar_increment;
> +	int default_value;
> +	int min_value;
> +	int max_value;
> +};
> +
> +struct str_data {
> +	struct kobject *attr_name_kobj;
> +	char display_name_language_code[MAX_BUFF];
> +	char attribute_name[MAX_BUFF];
> +	char display_name[MAX_BUFF];
> +	char default_value[MAX_BUFF];
> +	char dell_modifier[MAX_BUFF];
> +	int min_length;
> +	int max_length;
> +};
> +
> +struct po_data {
> +	struct kobject *attr_name_kobj;
> +	char attribute_name[MAX_BUFF];
> +	int min_password_length;
> +	int max_password_length;
> +};
> +
> +struct wmi_sysman_priv {
> +	char current_admin_password[MAX_BUFF];
> +	char current_system_password[MAX_BUFF];
> +	struct wmi_device *password_attr_wdev;
> +	struct wmi_device *bios_attr_wdev;
> +	struct kset *authentication_dir_kset;
> +	struct kset *main_dir_kset;
> +	struct device *class_dev;
> +	struct enumeration_data *enumeration_data;
> +	int enumeration_instances_count;
> +	struct integer_data *integer_data;
> +	int integer_instances_count;
> +	struct str_data *str_data;
> +	int str_instances_count;
> +	struct po_data *po_data;
> +	int po_instances_count;
> +	bool pending_changes;
> +	struct mutex mutex;
> +};
> +
> +/* global structure used by multiple WMI interfaces */
> +extern struct wmi_sysman_priv wmi_priv;
> +
> +enum { ENUM, INT, STR, PO };
> +
> +enum {
> +	ATTR_NAME,
> +	DISPL_NAME_LANG_CODE,
> +	DISPLAY_NAME,
> +	DEFAULT_VAL,
> +	CURRENT_VAL,
> +	MODIFIER
> +};
> +
> +#define get_instance_id(type)							\
> +static int get_##type##_instance_id(struct kobject *kobj)			\
> +{										\
> +	int i;									\
> +	for (i = 0; i <= wmi_priv.type##_instances_count; i++) {		\
> +		if (!(strcmp(kobj->name, wmi_priv.type##_data[i].attribute_name)))\
> +			return i;						\
> +	}									\
> +	return -EIO;								\
> +}
> +
> +#define attribute_s_property_show(name, type)					\
> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,	\
> +			   char *buf)						\
> +{										\
> +	int i = get_##type##_instance_id(kobj);					\
> +	if (i >= 0)								\
> +		return sprintf(buf, "%s\n", wmi_priv.type##_data[i].name);	\
> +	return 0;								\
> +}
> +
> +#define attribute_n_property_show(name, type)					\
> +static ssize_t name##_show(struct kobject *kobj, struct kobj_attribute *attr,	\
> +			   char *buf)						\
> +{										\
> +	int i = get_##type##_instance_id(kobj);					\
> +	if (i >= 0)								\
> +		return sprintf(buf, "%d\n", wmi_priv.type##_data[i].name);	\
> +	return 0;								\
> +}
> +
> +#define attribute_property_store(curr_val, type)				\
> +static ssize_t curr_val##_store(struct kobject *kobj,				\
> +				struct kobj_attribute *attr,			\
> +				const char *buf, size_t count)			\
> +{										\
> +	char *p, *buf_cp;							\
> +	int i, ret = -EIO;							\
> +	buf_cp = kstrdup(buf, GFP_KERNEL);					\
> +	if (!buf_cp)								\
> +		return -ENOMEM;							\
> +	p = memchr(buf_cp, '\n', count);					\
> +										\
> +	if (p != NULL)								\
> +		*p = '\0';							\
> +	i = get_##type##_instance_id(kobj);					\
> +	if (i >= 0)								\
> +		ret = validate_##type##_input(i, buf_cp);			\
> +	if (!ret)								\
> +		ret = set_attribute(kobj->name, buf_cp);			\
> +	kfree(buf_cp);								\
> +	return ret ? ret : count;						\
> +}
> +
> +union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
> +int get_instance_count(const char *guid_string);
> +void strlcpy_attr(char *dest, char *src);
> +
> +int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
> +			struct kobject *attr_name_kobj);
> +int alloc_enum_data(void);
> +void exit_enum_attributes(void);
> +
> +int populate_int_data(union acpi_object *integer_obj, int instance_id,
> +			struct kobject *attr_name_kobj);
> +int alloc_int_data(void);
> +void exit_int_attributes(void);
> +
> +int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj);
> +int alloc_str_data(void);
> +void exit_str_attributes(void);
> +
> +int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj);
> +int alloc_po_data(void);
> +void exit_po_attributes(void);
> +
> +int set_attribute(const char *a_name, const char *a_value);
> +int set_bios_defaults(u8 defType);
> +
> +void exit_bios_attr_set_interface(void);
> +int init_bios_attr_set_interface(void);
> +int map_wmi_error(int error_code);
> +size_t calculate_string_buffer(const char *str);
> +size_t calculate_security_buffer(char *authentication);
> +void populate_security_buffer(char *buffer, char *authentication);
> +ssize_t populate_string_buffer(char *buffer, size_t buffer_len, const char *str);
> +int set_new_password(const char *password_type, const char *new);
> +int init_bios_attr_pass_interface(void);
> +void exit_bios_attr_pass_interface(void);
> +
> +#endif
> diff --git a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
> new file mode 100644
> index 000000000000..692c1f4777bf
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
> @@ -0,0 +1,187 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to enumeration type attributes under
> + * BIOS Enumeration GUID for use with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman.h"
> +
> +get_instance_id(enumeration);
> +
> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +	int instance_id = get_enumeration_instance_id(kobj);
> +	union acpi_object *obj;
> +	ssize_t ret;
> +
> +	if (instance_id < 0)
> +		return instance_id;
> +
> +	/* need to use specific instance_id and guid combination to get right data */
> +	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +	if (!obj)
> +		return -EIO;
> +	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING)
> +		return -EINVAL;
> +	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
> +	kfree(obj);
> +	return ret;
> +}
> +
> +/**
> + * validate_enumeration_input() - Validate input of current_value against possible values
> + * @instance_id: The instance on which input is validated
> + * @buf: Input value
> + */
> +static int validate_enumeration_input(int instance_id, const char *buf)
> +{
> +	char *options, *tmp, *p;
> +	int ret = -EINVAL;
> +
> +	options = tmp = kstrdup(wmi_priv.enumeration_data[instance_id].possible_values,
> +				 GFP_KERNEL);
> +	if (!options)
> +		return -ENOMEM;
> +
> +	while ((p = strsep(&options, ";")) != NULL) {
> +		if (!*p)
> +			continue;
> +		if (!strcasecmp(p, buf)) {
> +			ret = 0;
> +			break;
> +		}
> +	}
> +
> +	kfree(tmp);
> +	return ret;
> +}
> +
> +attribute_s_property_show(display_name_language_code, enumeration);
> +static struct kobj_attribute displ_langcode =
> +		__ATTR_RO(display_name_language_code);
> +
> +attribute_s_property_show(display_name, enumeration);
> +static struct kobj_attribute displ_name =
> +		__ATTR_RO(display_name);
> +
> +attribute_s_property_show(default_value, enumeration);
> +static struct kobj_attribute default_val =
> +		__ATTR_RO(default_value);
> +
> +attribute_property_store(current_value, enumeration);
> +static struct kobj_attribute current_val =
> +		__ATTR_RW_MODE(current_value, 0600);
> +
> +attribute_s_property_show(dell_modifier, enumeration);
> +static struct kobj_attribute modifier =
> +		__ATTR_RO(dell_modifier);
> +
> +attribute_s_property_show(dell_value_modifier, enumeration);
> +static struct kobj_attribute value_modfr =
> +		__ATTR_RO(dell_value_modifier);
> +
> +attribute_s_property_show(possible_values, enumeration);
> +static struct kobj_attribute poss_val =
> +		__ATTR_RO(possible_values);
> +
> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			 char *buf)
> +{
> +	return sprintf(buf, "enumeration\n");
> +}
> +static struct kobj_attribute type =
> +		__ATTR_RO(type);
> +
> +static struct attribute *enumeration_attrs[] = {
> +	&displ_langcode.attr,
> +	&displ_name.attr,
> +	&default_val.attr,
> +	&current_val.attr,
> +	&modifier.attr,
> +	&value_modfr.attr,
> +	&poss_val.attr,
> +	&type.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group enumeration_attr_group = {
> +	.attrs = enumeration_attrs,
> +};
> +
> +int alloc_enum_data(void)
> +{
> +	int ret = 0;
> +
> +	wmi_priv.enumeration_instances_count =
> +		get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +	wmi_priv.enumeration_data = kcalloc(wmi_priv.enumeration_instances_count,
> +					sizeof(struct enumeration_data), GFP_KERNEL);
> +	if (!wmi_priv.enumeration_data) {
> +		wmi_priv.enumeration_instances_count = 0;
> +		ret = -ENOMEM;
> +	}
> +	return ret;
> +}
> +
> +/**
> + * populate_enum_data() - Populate all properties of an instance under enumeration attribute
> + * @enumeration_obj: ACPI object with enumeration data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + */
> +int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
> +			struct kobject *attr_name_kobj)
> +{
> +	int i, next_obj, value_modifier_count, possible_values_count;
> +
> +	wmi_priv.enumeration_data[instance_id].attr_name_kobj = attr_name_kobj;
> +	strlcpy_attr(wmi_priv.enumeration_data[instance_id].attribute_name,
> +		enumeration_obj[ATTR_NAME].string.pointer);
> +	strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name_language_code,
> +		enumeration_obj[DISPL_NAME_LANG_CODE].string.pointer);
> +	strlcpy_attr(wmi_priv.enumeration_data[instance_id].display_name,
> +		enumeration_obj[DISPLAY_NAME].string.pointer);
> +	strlcpy_attr(wmi_priv.enumeration_data[instance_id].default_value,
> +		enumeration_obj[DEFAULT_VAL].string.pointer);
> +	strlcpy_attr(wmi_priv.enumeration_data[instance_id].dell_modifier,
> +		enumeration_obj[MODIFIER].string.pointer);
> +
> +	next_obj = MODIFIER + 1;
> +
> +	value_modifier_count = (uintptr_t)enumeration_obj[next_obj].string.pointer;
> +
> +	for (i = 0; i < value_modifier_count; i++) {
> +		strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier,
> +			enumeration_obj[++next_obj].string.pointer);
> +		strcat(wmi_priv.enumeration_data[instance_id].dell_value_modifier, ";");
> +	}
> +
> +	possible_values_count = (uintptr_t) enumeration_obj[++next_obj].string.pointer;
> +
> +	for (i = 0; i < possible_values_count; i++) {
> +		strcat(wmi_priv.enumeration_data[instance_id].possible_values,
> +			enumeration_obj[++next_obj].string.pointer);
> +		strcat(wmi_priv.enumeration_data[instance_id].possible_values, ";");
> +	}
> +
> +	return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
> +}
> +
> +/**
> + * exit_enum_attributes() - Clear all attribute data
> + *
> + * Clears all data allocated for this group of attributes
> + */
> +void exit_enum_attributes(void)
> +{
> +	int instance_id;
> +
> +	for (instance_id = 0; instance_id < wmi_priv.enumeration_instances_count; instance_id++) {
> +		if (wmi_priv.enumeration_data[instance_id].attr_name_kobj)
> +			sysfs_remove_group(wmi_priv.enumeration_data[instance_id].attr_name_kobj,
> +								&enumeration_attr_group);
> +	}
> +	kfree(wmi_priv.enumeration_data);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
> new file mode 100644
> index 000000000000..62cd7dbe57fe
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
> @@ -0,0 +1,171 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to integer type attributes under BIOS Integer GUID for use with
> + * dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman.h"
> +
> +enum int_properties {MIN_VALUE = 6, MAX_VALUE, SCALAR_INCR};
> +
> +get_instance_id(integer);
> +
> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +	int instance_id = get_integer_instance_id(kobj);
> +	union acpi_object *obj;
> +	ssize_t ret;
> +
> +	if (instance_id < 0)
> +		return instance_id;
> +
> +	/* need to use specific instance_id and guid combination to get right data */
> +	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> +	if (!obj)
> +		return -EIO;
> +	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER)
> +		return -EINVAL;
> +	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[CURRENT_VAL].integer.value);
> +	kfree(obj);
> +	return ret;
> +}
> +
> +/**
> + * validate_integer_input() - Validate input of current_value against lower and upper bound
> + * @instance_id: The instance on which input is validated
> + * @buf: Input value
> + */
> +static int validate_integer_input(int instance_id, const char *buf)
> +{
> +	int in_val;
> +	int ret;
> +
> +	ret = kstrtoint(buf, 0, &in_val);
> +	if (ret)
> +		return ret;
> +	if (in_val < wmi_priv.integer_data[instance_id].min_value ||
> +			in_val > wmi_priv.integer_data[instance_id].max_value)
> +		return -EINVAL;
> +
> +	return ret;
> +}
> +
> +attribute_s_property_show(display_name_language_code, integer);
> +static struct kobj_attribute integer_displ_langcode =
> +	__ATTR_RO(display_name_language_code);
> +
> +attribute_s_property_show(display_name, integer);
> +static struct kobj_attribute integer_displ_name =
> +	__ATTR_RO(display_name);
> +
> +attribute_n_property_show(default_value, integer);
> +static struct kobj_attribute integer_default_val =
> +	__ATTR_RO(default_value);
> +
> +attribute_property_store(current_value, integer);
> +static struct kobj_attribute integer_current_val =
> +	__ATTR_RW_MODE(current_value, 0600);
> +
> +attribute_s_property_show(dell_modifier, integer);
> +static struct kobj_attribute integer_modifier =
> +	__ATTR_RO(dell_modifier);
> +
> +attribute_n_property_show(min_value, integer);
> +static struct kobj_attribute integer_lower_bound =
> +	__ATTR_RO(min_value);
> +
> +attribute_n_property_show(max_value, integer);
> +static struct kobj_attribute integer_upper_bound =
> +	__ATTR_RO(max_value);
> +
> +attribute_n_property_show(scalar_increment, integer);
> +static struct kobj_attribute integer_scalar_increment =
> +	__ATTR_RO(scalar_increment);
> +
> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			 char *buf)
> +{
> +	return sprintf(buf, "integer\n");
> +}
> +static struct kobj_attribute integer_type =
> +	__ATTR_RO(type);
> +
> +static struct attribute *integer_attrs[] = {
> +	&integer_displ_langcode.attr,
> +	&integer_displ_name.attr,
> +	&integer_default_val.attr,
> +	&integer_current_val.attr,
> +	&integer_modifier.attr,
> +	&integer_lower_bound.attr,
> +	&integer_upper_bound.attr,
> +	&integer_scalar_increment.attr,
> +	&integer_type.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group integer_attr_group = {
> +	.attrs = integer_attrs,
> +};
> +
> +int alloc_int_data(void)
> +{
> +	int ret = 0;
> +
> +	wmi_priv.integer_instances_count = get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> +	wmi_priv.integer_data = kcalloc(wmi_priv.integer_instances_count,
> +					sizeof(struct integer_data), GFP_KERNEL);
> +	if (!wmi_priv.integer_data) {
> +		wmi_priv.integer_instances_count = 0;
> +		ret = -ENOMEM;
> +	}
> +	return ret;
> +}
> +
> +/**
> + * populate_int_data() - Populate all properties of an instance under integer attribute
> + * @integer_obj: ACPI object with integer data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + */
> +int populate_int_data(union acpi_object *integer_obj, int instance_id,
> +			struct kobject *attr_name_kobj)
> +{
> +	wmi_priv.integer_data[instance_id].attr_name_kobj = attr_name_kobj;
> +	strlcpy_attr(wmi_priv.integer_data[instance_id].attribute_name,
> +		integer_obj[ATTR_NAME].string.pointer);
> +	strlcpy_attr(wmi_priv.integer_data[instance_id].display_name_language_code,
> +		integer_obj[DISPL_NAME_LANG_CODE].string.pointer);
> +	strlcpy_attr(wmi_priv.integer_data[instance_id].display_name,
> +		integer_obj[DISPLAY_NAME].string.pointer);
> +	wmi_priv.integer_data[instance_id].default_value =
> +		(uintptr_t)integer_obj[DEFAULT_VAL].string.pointer;
> +	strlcpy_attr(wmi_priv.integer_data[instance_id].dell_modifier,
> +		integer_obj[MODIFIER].string.pointer);
> +	wmi_priv.integer_data[instance_id].min_value =
> +		(uintptr_t)integer_obj[MIN_VALUE].string.pointer;
> +	wmi_priv.integer_data[instance_id].max_value =
> +		(uintptr_t)integer_obj[MAX_VALUE].string.pointer;
> +	wmi_priv.integer_data[instance_id].scalar_increment =
> +		(uintptr_t)integer_obj[SCALAR_INCR].string.pointer;
> +
> +	return sysfs_create_group(attr_name_kobj, &integer_attr_group);
> +}
> +
> +/**
> + * exit_int_attributes() - Clear all attribute data
> + *
> + * Clears all data allocated for this group of attributes
> + */
> +void exit_int_attributes(void)
> +{
> +	int instance_id;
> +
> +	for (instance_id = 0; instance_id < wmi_priv.integer_instances_count; instance_id++) {
> +		if (wmi_priv.integer_data[instance_id].attr_name_kobj)
> +			sysfs_remove_group(wmi_priv.integer_data[instance_id].attr_name_kobj,
> +								&integer_attr_group);
> +	}
> +	kfree(wmi_priv.integer_data);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
> new file mode 100644
> index 000000000000..0d11e48e2e63
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
> @@ -0,0 +1,192 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to password object type attributes under BIOS Password Object GUID for
> + * use with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman.h"
> +
> +enum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN};
> +
> +get_instance_id(po);
> +
> +static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr,
> +					  char *buf)
> +{
> +	int instance_id = get_po_instance_id(kobj);
> +	union acpi_object *obj;
> +	ssize_t ret;
> +
> +	if (instance_id < 0)
> +		return instance_id;
> +
> +	/* need to use specific instance_id and guid combination to get right data */
> +	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +	if (!obj)
> +		return -EIO;
> +	if (obj->package.elements[IS_PASS_SET].type != ACPI_TYPE_INTEGER)
> +		return -EINVAL;
> +	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[IS_PASS_SET].integer.value);
> +	kfree(obj);
> +	return ret;
> +}
> +
> +struct kobj_attribute po_is_pass_set =
> +		__ATTR_RO(is_enabled);
> +
> +static ssize_t current_password_store(struct kobject *kobj,
> +				      struct kobj_attribute *attr,
> +				      const char *buf, size_t count)
> +{
> +	char *target = NULL;
> +	int length;
> +
> +	length = strlen(buf);
> +	if (buf[length-1] == '\n')
> +		length--;
> +
> +	/* firmware does verifiation of min/max password length,
> +	 * hence only check for not exceeding MAX_BUFF here.
> +	 */
> +	if (length >= MAX_BUFF)
> +		return -EINVAL;
> +
> +	if (strcmp(kobj->name, "Admin") == 0)
> +		target = wmi_priv.current_admin_password;
> +	else if (strcmp(kobj->name, "System") == 0)
> +		target = wmi_priv.current_system_password;
> +	if (!target)
> +		return -EIO;
> +	memcpy(target, buf, length);
> +	target[length] = '\0';
> +
> +	return count;
> +}
> +
> +struct kobj_attribute po_current_password =
> +		__ATTR_WO(current_password);
> +
> +static ssize_t new_password_store(struct kobject *kobj,
> +				  struct kobj_attribute *attr,
> +				  const char *buf, size_t count)
> +{
> +	char *p, *buf_cp;
> +	int ret;
> +
> +	buf_cp = kstrdup(buf, GFP_KERNEL);
> +	if (!buf_cp)
> +		return -ENOMEM;
> +	p = memchr(buf_cp, '\n', count);
> +
> +	if (p != NULL)
> +		*p = '\0';
> +	if (strlen(buf_cp) > MAX_BUFF) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ret = set_new_password(kobj->name, buf_cp);
> +
> +out:
> +	kfree(buf_cp);
> +	return ret ? ret : count;
> +}
> +
> +struct kobj_attribute po_new_password =
> +		__ATTR_WO(new_password);
> +
> +attribute_n_property_show(min_password_length, po);
> +struct kobj_attribute po_min_pass_length =
> +		__ATTR_RO(min_password_length);
> +
> +attribute_n_property_show(max_password_length, po);
> +struct kobj_attribute po_max_pass_length =
> +		__ATTR_RO(max_password_length);
> +
> +static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			 char *buf)
> +{
> +	return sprintf(buf, "password\n");
> +}
> +
> +struct kobj_attribute po_mechanism =
> +	__ATTR_RO(mechanism);
> +
> +static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			 char *buf)
> +{
> +	if (strcmp(kobj->name, "Admin") == 0)
> +		return sprintf(buf, "bios-admin\n");
> +	else if (strcmp(kobj->name, "System") == 0)
> +		return sprintf(buf, "power-on\n");
> +	return -EIO;
> +}
> +
> +struct kobj_attribute po_role =
> +	__ATTR_RO(role);
> +
> +static struct attribute *po_attrs[] = {
> +	&po_is_pass_set.attr,
> +	&po_min_pass_length.attr,
> +	&po_max_pass_length.attr,
> +	&po_current_password.attr,
> +	&po_new_password.attr,
> +	&po_role.attr,
> +	&po_mechanism.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group po_attr_group = {
> +	.attrs = po_attrs,
> +};
> +
> +int alloc_po_data(void)
> +{
> +	int ret = 0;
> +
> +	wmi_priv.po_instances_count = get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +	wmi_priv.po_data = kcalloc(wmi_priv.po_instances_count, sizeof(struct po_data), GFP_KERNEL);
> +	if (!wmi_priv.po_data) {
> +		wmi_priv.po_instances_count = 0;
> +		ret = -ENOMEM;
> +	}
> +	return ret;
> +}
> +
> +/**
> + * populate_po_data() - Populate all properties of an instance under password object attribute
> + * @po_obj: ACPI object with password object data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + */
> +int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj)
> +{
> +	wmi_priv.po_data[instance_id].attr_name_kobj = attr_name_kobj;
> +	strlcpy_attr(wmi_priv.po_data[instance_id].attribute_name,
> +		     po_obj[ATTR_NAME].string.pointer);
> +	wmi_priv.po_data[instance_id].min_password_length =
> +		(uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
> +	wmi_priv.po_data[instance_id].max_password_length =
> +		(uintptr_t) po_obj[MAX_PASS_LEN].string.pointer;
> +
> +	return sysfs_create_group(attr_name_kobj, &po_attr_group);
> +}
> +
> +/**
> + * exit_po_attributes() - Clear all attribute data
> + *
> + * Clears all data allocated for this group of attributes
> + */
> +void exit_po_attributes(void)
> +{
> +	int instance_id;
> +
> +	for (instance_id = 0; instance_id < wmi_priv.po_instances_count; instance_id++) {
> +		if (wmi_priv.po_data[instance_id].attr_name_kobj)
> +			sysfs_remove_group(wmi_priv.po_data[instance_id].attr_name_kobj,
> +								&po_attr_group);
> +	}
> +	kfree(wmi_priv.po_data);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> new file mode 100644
> index 000000000000..5780b4d94759
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/passwordattr-interface.c
> @@ -0,0 +1,153 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to SET password methods under BIOS attributes interface GUID
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include <linux/wmi.h>
> +#include "dell-wmi-sysman.h"
> +
> +static int call_password_interface(struct wmi_device *wdev, char *in_args, size_t size)
> +{
> +	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
> +	struct acpi_buffer input;
> +	union acpi_object *obj;
> +	acpi_status status;
> +	int ret = -EIO;
> +
> +	input.length =  (acpi_size) size;
> +	input.pointer = in_args;
> +	status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);
> +	if (ACPI_FAILURE(status))
> +		return -EIO;
> +	obj = (union acpi_object *)output.pointer;
> +	if (obj->type == ACPI_TYPE_INTEGER)
> +		ret = obj->integer.value;
> +
> +	kfree(output.pointer);
> +	/* let userland know it may need to check is_password_set again */
> +	kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);
> +	return map_wmi_error(ret);
> +}
> +
> +/**
> + * set_new_password() - Sets a system admin password
> + * @password_type: The type of password to set
> + * @new: The new password
> + *
> + * Sets the password using plaintext interface
> + */
> +int set_new_password(const char *password_type, const char *new)
> +{
> +	size_t password_type_size, current_password_size, new_size;
> +	size_t security_area_size, buffer_size;
> +	char *buffer = NULL, *start;
> +	char *current_password;
> +	int ret;
> +
> +	mutex_lock(&wmi_priv.mutex);
> +	if (!wmi_priv.password_attr_wdev) {
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +	if (strcmp(password_type, "Admin") == 0) {
> +		current_password = wmi_priv.current_admin_password;
> +	} else if (strcmp(password_type, "System") == 0) {
> +		current_password = wmi_priv.current_system_password;
> +	} else {
> +		ret = -EINVAL;
> +		dev_err(&wmi_priv.password_attr_wdev->dev, "unknown password type %s\n",
> +			password_type);
> +		goto out;
> +	}
> +
> +	/* build/calculate buffer */
> +	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
> +	password_type_size = calculate_string_buffer(password_type);
> +	current_password_size = calculate_string_buffer(current_password);
> +	new_size = calculate_string_buffer(new);
> +	buffer_size = security_area_size + password_type_size + current_password_size + new_size;
> +	buffer = kzalloc(buffer_size, GFP_KERNEL);
> +	if (!buffer) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	/* build security area */
> +	populate_security_buffer(buffer, wmi_priv.current_admin_password);
> +
> +	/* build variables to set */
> +	start = buffer + security_area_size;
> +	ret = populate_string_buffer(start, password_type_size, password_type);
> +	if (ret < 0)
> +		goto out;
> +
> +	start += ret;
> +	ret = populate_string_buffer(start, current_password_size, current_password);
> +	if (ret < 0)
> +		goto out;
> +
> +	start += ret;
> +	ret = populate_string_buffer(start, new_size, new);
> +	if (ret < 0)
> +		goto out;
> +
> +	print_hex_dump_bytes("set new password data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
> +	ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);
> +	/* clear current_password here and use user input from wmi_priv.current_password */
> +	if (!ret)
> +		memset(current_password, 0, MAX_BUFF);
> +	/* explain to user the detailed failure reason */
> +	else if (ret == -EOPNOTSUPP)
> +		dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
> +	else if (ret == -EACCES)
> +		dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
> +
> +out:
> +	kfree(buffer);
> +	mutex_unlock(&wmi_priv.mutex);
> +
> +	return ret;
> +}
> +
> +static int bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *context)
> +{
> +	mutex_lock(&wmi_priv.mutex);
> +	wmi_priv.password_attr_wdev = wdev;
> +	mutex_unlock(&wmi_priv.mutex);
> +	return 0;
> +}
> +
> +static int bios_attr_pass_interface_remove(struct wmi_device *wdev)
> +{
> +	mutex_lock(&wmi_priv.mutex);
> +	wmi_priv.password_attr_wdev = NULL;
> +	mutex_unlock(&wmi_priv.mutex);
> +	return 0;
> +}
> +
> +static const struct wmi_device_id bios_attr_pass_interface_id_table[] = {
> +	{ .guid_string = DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID },
> +	{ },
> +};
> +static struct wmi_driver bios_attr_pass_interface_driver = {
> +	.driver = {
> +		.name = DRIVER_NAME"-password"
> +	},
> +	.probe = bios_attr_pass_interface_probe,
> +	.remove = bios_attr_pass_interface_remove,
> +	.id_table = bios_attr_pass_interface_id_table,
> +};
> +
> +int init_bios_attr_pass_interface(void)
> +{
> +	return wmi_driver_register(&bios_attr_pass_interface_driver);
> +}
> +
> +void exit_bios_attr_pass_interface(void)
> +{
> +	wmi_driver_unregister(&bios_attr_pass_interface_driver);
> +}
> +
> +MODULE_DEVICE_TABLE(wmi, bios_attr_pass_interface_id_table);
> diff --git a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
> new file mode 100644
> index 000000000000..3ff4a7f38469
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
> @@ -0,0 +1,157 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Functions corresponding to string type attributes under BIOS String GUID for use with
> + * dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#include "dell-wmi-sysman.h"
> +
> +enum string_properties {MIN_LEN = 6, MAX_LEN};
> +
> +get_instance_id(str);
> +
> +static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +	int instance_id = get_str_instance_id(kobj);
> +	union acpi_object *obj;
> +	ssize_t ret;
> +
> +	if (instance_id < 0)
> +		return -EIO;
> +
> +	/* need to use specific instance_id and guid combination to get right data */
> +	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> +	if (!obj)
> +		return -EIO;
> +	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING)
> +		return -EINVAL;
> +	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
> +	kfree(obj);
> +	return ret;
> +}
> +
> +/**
> + * validate_str_input() - Validate input of current_value against min and max lengths
> + * @instance_id: The instance on which input is validated
> + * @buf: Input value
> + */
> +static int validate_str_input(int instance_id, const char *buf)
> +{
> +	int in_len = strlen(buf);
> +
> +	if ((in_len < wmi_priv.str_data[instance_id].min_length) ||
> +			(in_len > wmi_priv.str_data[instance_id].max_length))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +attribute_s_property_show(display_name_language_code, str);
> +static struct kobj_attribute str_displ_langcode =
> +		__ATTR_RO(display_name_language_code);
> +
> +attribute_s_property_show(display_name, str);
> +static struct kobj_attribute str_displ_name =
> +		__ATTR_RO(display_name);
> +
> +attribute_s_property_show(default_value, str);
> +static struct kobj_attribute str_default_val =
> +		__ATTR_RO(default_value);
> +
> +attribute_property_store(current_value, str);
> +static struct kobj_attribute str_current_val =
> +		__ATTR_RW_MODE(current_value, 0600);
> +
> +attribute_s_property_show(dell_modifier, str);
> +static struct kobj_attribute str_modifier =
> +		__ATTR_RO(dell_modifier);
> +
> +attribute_n_property_show(min_length, str);
> +static struct kobj_attribute str_min_length =
> +		__ATTR_RO(min_length);
> +
> +attribute_n_property_show(max_length, str);
> +static struct kobj_attribute str_max_length =
> +		__ATTR_RO(max_length);
> +
> +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			 char *buf)
> +{
> +	return sprintf(buf, "string\n");
> +}
> +static struct kobj_attribute str_type =
> +	__ATTR_RO(type);
> +
> +static struct attribute *str_attrs[] = {
> +	&str_displ_langcode.attr,
> +	&str_displ_name.attr,
> +	&str_default_val.attr,
> +	&str_current_val.attr,
> +	&str_modifier.attr,
> +	&str_min_length.attr,
> +	&str_max_length.attr,
> +	&str_type.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group str_attr_group = {
> +	.attrs = str_attrs,
> +};
> +
> +int alloc_str_data(void)
> +{
> +	int ret = 0;
> +
> +	wmi_priv.str_instances_count = get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> +	wmi_priv.str_data = kcalloc(wmi_priv.str_instances_count,
> +					sizeof(struct str_data), GFP_KERNEL);
> +	if (!wmi_priv.str_data) {
> +		wmi_priv.str_instances_count = 0;
> +		ret = -ENOMEM;
> +	}
> +	return ret;
> +}
> +
> +/**
> + * populate_str_data() - Populate all properties of an instance under string attribute
> + * @str_obj: ACPI object with integer data
> + * @instance_id: The instance to enumerate
> + * @attr_name_kobj: The parent kernel object
> + */
> +int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobject *attr_name_kobj)
> +{
> +	wmi_priv.str_data[instance_id].attr_name_kobj = attr_name_kobj;
> +	strlcpy_attr(wmi_priv.str_data[instance_id].attribute_name,
> +		     str_obj[ATTR_NAME].string.pointer);
> +	strlcpy_attr(wmi_priv.str_data[instance_id].display_name_language_code,
> +		     str_obj[DISPL_NAME_LANG_CODE].string.pointer);
> +	strlcpy_attr(wmi_priv.str_data[instance_id].display_name,
> +		     str_obj[DISPLAY_NAME].string.pointer);
> +	strlcpy_attr(wmi_priv.str_data[instance_id].default_value,
> +		     str_obj[DEFAULT_VAL].string.pointer);
> +	strlcpy_attr(wmi_priv.str_data[instance_id].dell_modifier,
> +		     str_obj[MODIFIER].string.pointer);
> +	wmi_priv.str_data[instance_id].min_length = (uintptr_t)str_obj[MIN_LEN].string.pointer;
> +	wmi_priv.str_data[instance_id].max_length = (uintptr_t) str_obj[MAX_LEN].string.pointer;
> +
> +	return sysfs_create_group(attr_name_kobj, &str_attr_group);
> +}
> +
> +/**
> + * exit_str_attributes() - Clear all attribute data
> + *
> + * Clears all data allocated for this group of attributes
> + */
> +void exit_str_attributes(void)
> +{
> +	int instance_id;
> +
> +	for (instance_id = 0; instance_id < wmi_priv.str_instances_count; instance_id++) {
> +		if (wmi_priv.str_data[instance_id].attr_name_kobj)
> +			sysfs_remove_group(wmi_priv.str_data[instance_id].attr_name_kobj,
> +								&str_attr_group);
> +	}
> +	kfree(wmi_priv.str_data);
> +}
> diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> new file mode 100644
> index 000000000000..3842575a6c18
> --- /dev/null
> +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> @@ -0,0 +1,625 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Common methods for use with dell-wmi-sysman
> + *
> + *  Copyright (c) 2020 Dell Inc.
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/fs.h>
> +#include <linux/dmi.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/wmi.h>
> +#include "dell-wmi-sysman.h"
> +
> +#define MAX_TYPES  4
> +#include <linux/nls.h>
> +
> +static struct class firmware_attributes_class = {
> +	.name = "firmware-attributes",
> +};
> +
> +struct wmi_sysman_priv wmi_priv = {
> +	.mutex = __MUTEX_INITIALIZER(wmi_priv.mutex),
> +};
> +
> +/* reset bios to defaults */
> +static const char * const reset_types[] = {"builtinsafe", "lastknowngood", "factory", "custom"};
> +static int reset_option = -1;
> +
> +
> +/**
> + * populate_string_buffer() - populates a string buffer
> + * @buffer: the start of the destination buffer
> + * @buffer_len: length of the destination buffer
> + * @str: the string to insert into buffer
> + */
> +ssize_t populate_string_buffer(char *buffer, size_t buffer_len, const char *str)
> +{
> +	u16 *length = (u16 *)buffer;
> +	u16 *target = length + 1;
> +	int ret;
> +
> +	ret = utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN,
> +			      target, buffer_len - sizeof(u16));
> +	if (ret < 0) {
> +		dev_err(wmi_priv.class_dev, "UTF16 conversion failed\n");
> +		return ret;
> +	}
> +
> +	if ((ret * sizeof(u16)) > U16_MAX) {
> +		dev_err(wmi_priv.class_dev, "Error string too long\n");
> +		return -ERANGE;
> +	}
> +
> +	*length = ret * sizeof(u16);
> +	return sizeof(u16) + *length;
> +}
> +
> +/**
> + * calculate_string_buffer() - determines size of string buffer for use with BIOS communication
> + * @str: the string to calculate based upon
> + *
> + */
> +size_t calculate_string_buffer(const char *str)
> +{
> +	/* u16 length field + one UTF16 char for each input char */
> +	return sizeof(u16) + strlen(str) * sizeof(u16);
> +}
> +
> +/**
> + * calculate_security_buffer() - determines size of security buffer for authentication scheme
> + * @authentication: the authentication content
> + *
> + * Currently only supported type is Admin password
> + */
> +size_t calculate_security_buffer(char *authentication)
> +{
> +	if (strlen(authentication) > 0) {
> +		return (sizeof(u32) * 2) + strlen(authentication) +
> +			strlen(authentication) % 2;
> +	}
> +	return sizeof(u32) * 2;
> +}
> +
> +/**
> + * populate_security_buffer() - builds a security buffer for authentication scheme
> + * @buffer: the buffer to populate
> + * @authentication: the authentication content
> + *
> + * Currently only supported type is PLAIN TEXT
> + */
> +void populate_security_buffer(char *buffer, char *authentication)
> +{
> +	char *auth = buffer + sizeof(u32) * 2;
> +	u32 *sectype = (u32 *) buffer;
> +	u32 *seclen = sectype + 1;
> +
> +	*sectype = strlen(authentication) > 0 ? 1 : 0;
> +	*seclen = strlen(authentication);
> +
> +	/* plain text */
> +	if (strlen(authentication) > 0)
> +		memcpy(auth, authentication, *seclen);
> +}
> +
> +/**
> + * map_wmi_error() - map errors from WMI methods to kernel error codes
> + * @error_code: integer error code returned from Dell's firmware
> + */
> +int map_wmi_error(int error_code)
> +{
> +	switch (error_code) {
> +	case 0:
> +		/* success */
> +		return 0;
> +	case 1:
> +		/* failed */
> +		return -EIO;
> +	case 2:
> +		/* invalid parameter */
> +		return -EINVAL;
> +	case 3:
> +		/* access denied */
> +		return -EACCES;
> +	case 4:
> +		/* not supported */
> +		return -EOPNOTSUPP;
> +	case 5:
> +		/* memory error */
> +		return -ENOMEM;
> +	case 6:
> +		/* protocol error */
> +		return -EPROTO;
> +	}
> +	/* unspecified error */
> +	return -EIO;
> +}
> +
> +/**
> + * reset_bios_show() - sysfs implementaton for read reset_bios
> + * @kobj: Kernel object for this attribute
> + * @attr: Kernel object attribute
> + * @buf: The buffer to display to userspace
> + */
> +static ssize_t reset_bios_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +	char *start = buf;
> +	int i;
> +
> +	for (i = 0; i < MAX_TYPES; i++) {
> +		if (i == reset_option)
> +			buf += sprintf(buf, "[%s] ", reset_types[i]);
> +		else
> +			buf += sprintf(buf, "%s ", reset_types[i]);
> +	}
> +	buf += sprintf(buf, "\n");
> +	return buf-start;
> +}
> +
> +/**
> + * reset_bios_store() - sysfs implementaton for write reset_bios
> + * @kobj: Kernel object for this attribute
> + * @attr: Kernel object attribute
> + * @buf: The buffer from userspace
> + * @count: the size of the buffer from userspace
> + */
> +static ssize_t reset_bios_store(struct kobject *kobj,
> +				struct kobj_attribute *attr, const char *buf, size_t count)
> +{
> +	int type = sysfs_match_string(reset_types, buf);
> +	int ret;
> +
> +	if (type < 0)
> +		return type;
> +
> +	ret = set_bios_defaults(type);
> +	pr_debug("reset all attributes request type %d: %d\n", type, ret);
> +	if (!ret) {
> +		reset_option = type;
> +		ret = count;
> +	}
> +
> +	return ret;
> +}
> +
> +/**
> + * pending_reboot_show() - sysfs implementaton for read pending_reboot
> + * @kobj: Kernel object for this attribute
> + * @attr: Kernel object attribute
> + * @buf: The buffer to display to userspace
> + *
> + * Stores default value as 0
> + * When current_value is changed this attribute is set to 1 to notify reboot may be required
> + */
> +static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr,
> +				   char *buf)
> +{
> +	return sprintf(buf, "%d\n", wmi_priv.pending_changes);
> +}
> +
> +static struct kobj_attribute reset_bios = __ATTR_RW(reset_bios);
> +static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
> +
> +
> +/**
> + * create_attributes_level_sysfs_files() - Creates reset_bios and
> + * pending_reboot attributes
> + */
> +static int create_attributes_level_sysfs_files(void)
> +{
> +	int ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
> +
> +	if (ret) {
> +		pr_debug("could not create reset_bios file\n");
> +		return ret;
> +	}
> +
> +	ret = sysfs_create_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
> +	if (ret) {
> +		pr_debug("could not create changing_pending_reboot file\n");
> +		sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
> +	}
> +	return ret;
> +}
> +
> +static void release_reset_bios_data(void)
> +{
> +	sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &reset_bios.attr);
> +	sysfs_remove_file(&wmi_priv.main_dir_kset->kobj, &pending_reboot.attr);
> +}
> +
> +static ssize_t wmi_sysman_attr_show(struct kobject *kobj, struct attribute *attr,
> +				    char *buf)
> +{
> +	struct kobj_attribute *kattr;
> +	ssize_t ret = -EIO;
> +
> +	kattr = container_of(attr, struct kobj_attribute, attr);
> +	if (kattr->show)
> +		ret = kattr->show(kobj, kattr, buf);
> +	return ret;
> +}
> +
> +static ssize_t wmi_sysman_attr_store(struct kobject *kobj, struct attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	struct kobj_attribute *kattr;
> +	ssize_t ret = -EIO;
> +
> +	kattr = container_of(attr, struct kobj_attribute, attr);
> +	if (kattr->store)
> +		ret = kattr->store(kobj, kattr, buf, count);
> +	return ret;
> +}
> +
> +const struct sysfs_ops wmi_sysman_kobj_sysfs_ops = {
> +	.show	= wmi_sysman_attr_show,
> +	.store	= wmi_sysman_attr_store,
> +};
> +
> +static void attr_name_release(struct kobject *kobj)
> +{
> +	kfree(kobj);
> +}
> +
> +static struct kobj_type attr_name_ktype = {
> +	.release	= attr_name_release,
> +	.sysfs_ops	= &wmi_sysman_kobj_sysfs_ops,
> +};
> +
> +/**
> + * strlcpy_attr - Copy a length-limited, NULL-terminated string with bound checks
> + * @dest: Where to copy the string to
> + * @src: Where to copy the string from
> + */
> +void strlcpy_attr(char *dest, char *src)
> +{
> +	size_t len = strlen(src) + 1;
> +
> +	if (len > 1 && len <= MAX_BUFF)
> +		strlcpy(dest, src, len);
> +
> +	/*len can be zero because any property not-applicable to attribute can
> +	 * be empty so check only for too long buffers and log error
> +	 */
> +	if (len > MAX_BUFF)
> +		pr_err("Source string returned from BIOS is out of bound!\n");
> +}
> +
> +/**
> + * get_wmiobj_pointer() - Get Content of WMI block for particular instance
> + * @instance_id: WMI instance ID
> + * @guid_string: WMI GUID (in str form)
> + *
> + * Fetches the content for WMI block (instance_id) under GUID (guid_string)
> + * Caller must kfree the return
> + */
> +union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string)
> +{
> +	struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
> +	acpi_status status;
> +
> +	status = wmi_query_block(guid_string, instance_id, &out);
> +
> +	return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
> +}
> +
> +/**
> + * get_instance_count() - Compute total number of instances under guid_string
> + * @guid_string: WMI GUID (in string form)
> + */
> +int get_instance_count(const char *guid_string)
> +{
> +	union acpi_object *wmi_obj = NULL;
> +	int i = 0;
> +
> +	do {
> +		kfree(wmi_obj);
> +		wmi_obj = get_wmiobj_pointer(i, guid_string);
> +		i++;
> +	} while (wmi_obj);
> +
> +	return (i-1);
> +}
> +
> +/**
> + * alloc_attributes_data() - Allocate attributes data for a particular type
> + * @attr_type: Attribute type to allocate
> + */
> +static int alloc_attributes_data(int attr_type)
> +{
> +	int retval = 0;
> +
> +	switch (attr_type) {
> +	case ENUM:
> +		retval = alloc_enum_data();
> +		break;
> +	case INT:
> +		retval = alloc_int_data();
> +		break;
> +	case STR:
> +		retval = alloc_str_data();
> +		break;
> +	case PO:
> +		retval = alloc_po_data();
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return retval;
> +}
> +
> +/**
> + * destroy_attribute_objs() - Free a kset of kobjects
> + * @kset: The kset to destroy
> + *
> + * Fress kobjects created for each attribute_name under attribute type kset
> + */
> +static void destroy_attribute_objs(struct kset *kset)
> +{
> +	struct kobject *pos, *next;
> +
> +	list_for_each_entry_safe(pos, next, &kset->list, entry) {
> +		kobject_put(pos);
> +	}
> +}
> +
> +/**
> + * release_attributes_data() - Clean-up all sysfs directories and files created
> + */
> +static void release_attributes_data(void)
> +{
> +	release_reset_bios_data();
> +
> +	mutex_lock(&wmi_priv.mutex);
> +	exit_enum_attributes();
> +	exit_int_attributes();
> +	exit_str_attributes();
> +	exit_po_attributes();
> +	if (wmi_priv.authentication_dir_kset) {
> +		destroy_attribute_objs(wmi_priv.authentication_dir_kset);
> +		kset_unregister(wmi_priv.authentication_dir_kset);
> +		wmi_priv.authentication_dir_kset = NULL;
> +	}
> +	if (wmi_priv.main_dir_kset) {
> +		destroy_attribute_objs(wmi_priv.main_dir_kset);
> +		kset_unregister(wmi_priv.main_dir_kset);
> +	}
> +	mutex_unlock(&wmi_priv.mutex);
> +
> +}
> +
> +/**
> + * init_bios_attributes() - Initialize all attributes for a type
> + * @attr_type: The attribute type to initialize
> + * @guid: The WMI GUID associated with this type to initialize
> + *
> + * Initialiaze all 4 types of attributes enumeration, integer, string and password object.
> + * Populates each attrbute typ's respective properties under sysfs files
> + */
> +static int init_bios_attributes(int attr_type, const char *guid)
> +{
> +	struct kobject *attr_name_kobj; //individual attribute names
> +	union acpi_object *obj = NULL;
> +	union acpi_object *elements;
> +	struct kset *tmp_set;
> +
> +	/* instance_id needs to be reset for each type GUID
> +	 * also, instance IDs are unique within GUID but not across
> +	 */
> +	int instance_id = 0;
> +	int retval = 0;
> +
> +	retval = alloc_attributes_data(attr_type);
> +	if (retval)
> +		return retval;
> +	/* need to use specific instance_id and guid combination to get right data */
> +	obj = get_wmiobj_pointer(instance_id, guid);
> +	if (!obj)
> +		return -ENODEV;
> +	elements = obj->package.elements;
> +
> +	mutex_lock(&wmi_priv.mutex);
> +	while (elements) {
> +		/* sanity checking */
> +		if (strlen(elements[ATTR_NAME].string.pointer) == 0) {
> +			pr_debug("empty attribute found\n");
> +			goto nextobj;
> +		}
> +		if (attr_type == PO)
> +			tmp_set = wmi_priv.authentication_dir_kset;
> +		else
> +			tmp_set = wmi_priv.main_dir_kset;
> +
> +		if (kset_find_obj(tmp_set, elements[ATTR_NAME].string.pointer)) {
> +			pr_debug("duplicate attribute name found - %s\n",
> +				elements[ATTR_NAME].string.pointer);
> +			goto nextobj;
> +		}
> +
> +		/* build attribute */
> +		attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
> +		if (!attr_name_kobj)
> +			goto err_attr_init;
> +
> +		attr_name_kobj->kset = tmp_set;
> +
> +		retval = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, NULL, "%s",
> +						elements[ATTR_NAME].string.pointer);
> +		if (retval) {
> +			kobject_put(attr_name_kobj);
> +			goto err_attr_init;
> +		}
> +
> +		/* enumerate all of this attribute */
> +		switch (attr_type) {
> +		case ENUM:
> +			retval = populate_enum_data(elements, instance_id, attr_name_kobj);
> +			break;
> +		case INT:
> +			retval = populate_int_data(elements, instance_id, attr_name_kobj);
> +			break;
> +		case STR:
> +			retval = populate_str_data(elements, instance_id, attr_name_kobj);
> +			break;
> +		case PO:
> +			retval = populate_po_data(elements, instance_id, attr_name_kobj);
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		if (retval) {
> +			pr_debug("failed to populate %s\n",
> +				elements[ATTR_NAME].string.pointer);
> +			goto err_attr_init;
> +		}
> +
> +nextobj:
> +		kfree(obj);
> +		instance_id++;
> +		obj = get_wmiobj_pointer(instance_id, guid);
> +		elements = obj ? obj->package.elements : NULL;
> +	}
> +
> +	goto out;
> +
> +err_attr_init:
> +	release_attributes_data();
> +	kfree(obj);
> +out:
> +	mutex_unlock(&wmi_priv.mutex);
> +	return retval;
> +}
> +
> +static int __init sysman_init(void)
> +{
> +	int ret = 0;
> +
> +	if (!dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL) &&
> +	    !dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "www.dell.com", NULL)) {
> +		pr_err("Unable to run on non-Dell system\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = init_bios_attr_set_interface();
> +	if (ret || !wmi_priv.bios_attr_wdev) {
> +		pr_debug("failed to initialize set interface\n");
> +		goto fail_set_interface;
> +	}
> +
> +	ret = init_bios_attr_pass_interface();
> +	if (ret || !wmi_priv.password_attr_wdev) {
> +		pr_debug("failed to initialize pass interface\n");
> +		goto fail_pass_interface;
> +	}
> +
> +	ret = class_register(&firmware_attributes_class);
> +	if (ret)
> +		goto fail_class;
> +
> +	wmi_priv.class_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0),
> +				  NULL, "%s", DRIVER_NAME);
> +	if (IS_ERR(wmi_priv.class_dev)) {
> +		ret = PTR_ERR(wmi_priv.class_dev);
> +		goto fail_classdev;
> +	}
> +
> +	wmi_priv.main_dir_kset = kset_create_and_add("attributes", NULL,
> +						     &wmi_priv.class_dev->kobj);
> +	if (!wmi_priv.main_dir_kset) {
> +		ret = -ENOMEM;
> +		goto fail_main_kset;
> +	}
> +
> +	wmi_priv.authentication_dir_kset = kset_create_and_add("authentication", NULL,
> +								&wmi_priv.class_dev->kobj);
> +	if (!wmi_priv.authentication_dir_kset) {
> +		ret = -ENOMEM;
> +		goto fail_authentication_kset;
> +	}
> +
> +	ret = create_attributes_level_sysfs_files();
> +	if (ret) {
> +		pr_debug("could not create reset BIOS attribute\n");
> +		goto fail_reset_bios;
> +	}
> +
> +	ret = init_bios_attributes(ENUM, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +	if (ret) {
> +		pr_debug("failed to populate enumeration type attributes\n");
> +		goto fail_create_group;
> +	}
> +
> +	ret = init_bios_attributes(INT, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> +	if (ret) {
> +		pr_debug("failed to populate integer type attributes\n");
> +		goto fail_create_group;
> +	}
> +
> +	ret = init_bios_attributes(STR, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> +	if (ret) {
> +		pr_debug("failed to populate string type attributes\n");
> +		goto fail_create_group;
> +	}
> +
> +	ret = init_bios_attributes(PO, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +	if (ret) {
> +		pr_debug("failed to populate pass object type attributes\n");
> +		goto fail_create_group;
> +	}
> +
> +	return 0;
> +
> +fail_create_group:
> +	release_attributes_data();
> +
> +fail_reset_bios:
> +	if (wmi_priv.authentication_dir_kset) {
> +		kset_unregister(wmi_priv.authentication_dir_kset);
> +		wmi_priv.authentication_dir_kset = NULL;
> +	}
> +
> +fail_authentication_kset:
> +	if (wmi_priv.main_dir_kset) {
> +		kset_unregister(wmi_priv.main_dir_kset);
> +		wmi_priv.main_dir_kset = NULL;
> +	}
> +
> +fail_main_kset:
> +	device_destroy(&firmware_attributes_class, MKDEV(0, 0));
> +
> +fail_classdev:
> +	class_unregister(&firmware_attributes_class);
> +
> +fail_class:
> +	exit_bios_attr_pass_interface();
> +
> +fail_pass_interface:
> +	exit_bios_attr_set_interface();
> +
> +fail_set_interface:
> +	return ret;
> +}
> +
> +static void __exit sysman_exit(void)
> +{
> +	release_attributes_data();
> +	device_destroy(&firmware_attributes_class, MKDEV(0, 0));
> +	class_unregister(&firmware_attributes_class);
> +	exit_bios_attr_set_interface();
> +	exit_bios_attr_pass_interface();
> +}
> +
> +module_init(sysman_init);
> +module_exit(sysman_exit);
> +
> +MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
> +MODULE_AUTHOR("Prasanth Ksr <prasanth.ksr@dell.com>");
> +MODULE_AUTHOR("Divya Bharathi <divya.bharathi@dell.com>");
> +MODULE_DESCRIPTION("Dell platform setting control interface");
> +MODULE_LICENSE("GPL");
> 


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

* Re: [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-10-27 13:49 [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems Divya Bharathi
  2020-10-28  9:57 ` Hans de Goede
@ 2020-10-29  8:01 ` Mauro Carvalho Chehab
  2020-10-29  9:31   ` [PATCH] docs: ABI: sysfs-class-firmware-attributes: solve some warnings Mauro Carvalho Chehab
  2020-10-29 10:03   ` [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems Mauro Carvalho Chehab
  1 sibling, 2 replies; 6+ messages in thread
From: Mauro Carvalho Chehab @ 2020-10-29  8:01 UTC (permalink / raw)
  To: Divya Bharathi
  Cc: dvhart, LKML, platform-driver-x86, Divya Bharathi, Hans de Goede,
	Andy Shevchenko, mark gross, Mario Limonciello, Prasanth KSR

Em Tue, 27 Oct 2020 19:19:44 +0530
Divya Bharathi <divya27392@gmail.com> escreveu:

> The Dell WMI Systems Management Driver provides a sysfs
> interface for systems management to enable BIOS configuration
> capability on certain Dell Systems.
> 
> This driver allows user to configure Dell systems with a
> uniform common interface. To facilitate this, the patch
> introduces a generic way for driver to be able to create
> configurable BIOS Attributes available in Setup (F2) screen.
> 
> Cc: Hans de Goede <hdegoede@redhat.com>
> Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
> Cc: mark gross <mgross@linux.intel.com>
> 
> Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> Co-developed-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
> Signed-off-by: Divya Bharathi <divya.bharathi@dell.com>
> ---


> +What:		/sys/class/firmware-attributes/*/authentication/
> +Date:		February 2021
> +KernelVersion:	5.11
> +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> +		Mario Limonciello <mario.limonciello@dell.com>,
> +		Prasanth KSR <prasanth.ksr@dell.com>
> +
> +		Devices support various authentication mechanisms which can be exposed
> +		as a separate configuration object.
> +
> +		For example a "BIOS Admin" password and "System" Password can be set,
> +		reset or cleared using these attributes.
> +		- An "Admin" password is used for preventing modification to the BIOS
> +		  settings.
> +		- A "System" password is required to boot a machine.
> +

This is adding a new warning:

	$ ./scripts/get_abi.pl validate
	Warning: file Documentation/ABI/testing/sysfs-class-firmware-attributes#172:
		What '/sys/class/firmware-attributes/*/authentication/' doesn't have a description

Because you forgot to add a Description: tag.

Feel free to either add the enclosed tag to the tree which added this into
linux-next, or to fold id with the original patch.

Thanks,
Mauro

ABI: docs: sysfs-class-firmware-attributes: add a missing tag
    
The Description:  tag is missing, causing this warning with
scripts/get_abi.pl:
    
	Warning: file Documentation/ABI/testing/sysfs-class-firmware-attributes#172:
		 What '/sys/class/firmware-attributes/*/authentication/' doesn't have a description
    
Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems")
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
index 04a15c72e883..ea1837f1f3c2 100644
--- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
+++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
@@ -113,7 +113,7 @@ KernelVersion:	5.11
 Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
 		Mario Limonciello <mario.limonciello@dell.com>,
 		Prasanth KSR <prasanth.ksr@dell.com>
-
+Description:
 		Devices support various authentication mechanisms which can be exposed
 		as a separate configuration object.
 


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

* [PATCH] docs: ABI: sysfs-class-firmware-attributes: solve some warnings
  2020-10-29  8:01 ` Mauro Carvalho Chehab
@ 2020-10-29  9:31   ` Mauro Carvalho Chehab
  2020-11-03  9:35     ` Hans de Goede
  2020-10-29 10:03   ` [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems Mauro Carvalho Chehab
  1 sibling, 1 reply; 6+ messages in thread
From: Mauro Carvalho Chehab @ 2020-10-29  9:31 UTC (permalink / raw)
  To: Linux Doc Mailing List, Divya Bharathi
  Cc: Mauro Carvalho Chehab, Andy Shevchenko, Divya Bharathi,
	Greg Kroah-Hartman, Hans de Goede, Jonathan Corbet, LKML,
	Mario Limonciello, Prasanth KSR, mark gross, dvhart,
	platform-driver-x86

The Description: tag is missing on some places, causing
scripts/get_abi.pl warnings:

	Warning: file Documentation/ABI/testing/sysfs-class-firmware-attributes#172:
		What '/sys/class/firmware-attributes/*/authentication/' doesn't have a description

Also, some warnings are produced when generating html documentation:

	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Title underline too short.

	Dell specific class extensions
	--------------------------
	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Unexpected indentation.
	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Unexpected indentation.
	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Block quote ends without a blank line; unexpected unindent.
	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:173: WARNING: Unexpected indentation.
	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:173: WARNING: Unexpected indentation.
	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:173: WARNING: Block quote ends without a blank line; unexpected unindent.
	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:111: WARNING: Inline emphasis start-string without end-string.

Address the warnings, making it to produce the expected
output for the documentation ABI.

Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
 .../testing/sysfs-class-firmware-attributes   | 138 +++++++++++-------
 1 file changed, 86 insertions(+), 52 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
index 04a15c72e883..8ea59fea4709 100644
--- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
+++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
@@ -12,17 +12,20 @@ Description:
 		Unless otherwise specified in an attribute description all attributes are optional
 		and will accept UTF-8 input.
 
-		type: A file that can be read to obtain the type of attribute.  This attribute is
-			mandatory.
+		type:
+		    A file that can be read to obtain the type of attribute.
+		    This attribute is mandatory.
 
 		The following are known types:
+
 			- enumeration: a set of pre-defined valid values
 			- integer: a range of numerical values
 			- string
 
 		All attribute types support the following values:
 
-		current_value:	A file that can be read to obtain the current
+		current_value:
+				A file that can be read to obtain the current
 				value of the <attr>.
 
 				This file can also be written to in order to update the value of a
@@ -30,59 +33,71 @@ Description:
 
 				This attribute is mandatory.
 
-		default_value:	A file that can be read to obtain the default
+		default_value:
+				A file that can be read to obtain the default
 				value of the <attr>
 
-		display_name:	A file that can be read to obtain a user friendly
+		display_name:
+				A file that can be read to obtain a user friendly
 				description of the at <attr>
 
-		display_name_language_code:	A file that can be read to obtain
+		display_name_language_code:
+						A file that can be read to obtain
 						the IETF language tag corresponding to the
 						"display_name" of the <attr>
 
 		"enumeration"-type specific properties:
 
-		possible_values:	A file that can be read to obtain the possible
+		possible_values:
+					A file that can be read to obtain the possible
 					values of the <attr>. Values are separated using
 					semi-colon (``;``).
 
 		"integer"-type specific properties:
 
-		min_value:	A file that can be read to obtain the lower
+		min_value:
+				A file that can be read to obtain the lower
 				bound value of the <attr>
 
-		max_value:	A file that can be read to obtain the upper
+		max_value:
+				A file that can be read to obtain the upper
 				bound value of the <attr>
 
-		scalar_increment:	A file that can be read to obtain the scalar value used for
+		scalar_increment:
+					A file that can be read to obtain the scalar value used for
 					increments of current_value this attribute accepts.
 
 		"string"-type specific properties:
 
-		max_length:	A file that can be read to obtain the maximum
+		max_length:
+				A file that can be read to obtain the maximum
 				length value of the <attr>
 
-		min_length:	A file that can be read to obtain the minimum
+		min_length:
+				A file that can be read to obtain the minimum
 				length value of the <attr>
 
 		Dell specific class extensions
-		--------------------------
+		------------------------------
 
 		On Dell systems the following additional attributes are available:
 
-		dell_modifier:	A file that can be read to obtain attribute-level
+		dell_modifier:
+				A file that can be read to obtain attribute-level
 				dependency rule. It says an attribute X will become read-only or
 				suppressed, if/if-not attribute Y is configured.
 
-				modifier rules can be in following format:
-				[ReadOnlyIf:<attribute>=<value>]
-				[ReadOnlyIfNot:<attribute>=<value>]
-				[SuppressIf:<attribute>=<value>]
-				[SuppressIfNot:<attribute>=<value>]
+				modifier rules can be in following format::
 
-				For example:
-				AutoOnFri/dell_modifier has value,
-					[SuppressIfNot:AutoOn=SelectDays]
+				    [ReadOnlyIf:<attribute>=<value>]
+				    [ReadOnlyIfNot:<attribute>=<value>]
+				    [SuppressIf:<attribute>=<value>]
+				    [SuppressIfNot:<attribute>=<value>]
+
+				For example::
+
+				    AutoOnFri/dell_modifier has value,
+					    [SuppressIfNot:AutoOn=SelectDays]
 
 				This means AutoOnFri will be suppressed in BIOS setup if AutoOn
 				attribute is not "SelectDays" and its value will not be effective
@@ -90,18 +105,22 @@ Description:
 
 		Enumeration attributes also support the following:
 
-		dell_value_modifier:	A file that can be read to obtain value-level dependency.
+		dell_value_modifier:
+					A file that can be read to obtain value-level dependency.
 					This file is similar to dell_modifier but here,	an
 					attribute's current value will be forcefully changed based
 					dependent attributes value.
 
-					dell_value_modifier rules can be in following format:
-					<value>[ForceIf:<attribute>=<value>]
-					<value>[ForceIfNot:<attribute>=<value>]
+					dell_value_modifier rules can be in following format::
+
+					    <value>[ForceIf:<attribute>=<value>]
+					    <value>[ForceIfNot:<attribute>=<value>]
+
+					For example:
+
+					    LegacyOrom/dell_value_modifier has value:
+						    Disabled[ForceIf:SecureBoot=Enabled]
 
-					For example,
-					LegacyOrom/dell_value_modifier has value:
-						Disabled[ForceIf:SecureBoot=Enabled]
 					This means LegacyOrom's current value will be forced to
 					"Disabled" in BIOS setup if SecureBoot is Enabled and its
 					value will not be effective through sysfs until this rule is
@@ -113,12 +132,13 @@ KernelVersion:	5.11
 Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
 		Mario Limonciello <mario.limonciello@dell.com>,
 		Prasanth KSR <prasanth.ksr@dell.com>
-
+Description:
 		Devices support various authentication mechanisms which can be exposed
 		as a separate configuration object.
 
 		For example a "BIOS Admin" password and "System" Password can be set,
 		reset or cleared using these attributes.
+
 		- An "Admin" password is used for preventing modification to the BIOS
 		  settings.
 		- A "System" password is required to boot a machine.
@@ -126,39 +146,50 @@ Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
 		Change in any of these two authentication methods will also generate an
 		uevent KOBJ_CHANGE.
 
-		is_enabled:		A file that can be read to obtain a 0/1 flag to see if
+		is_enabled:
+					A file that can be read to obtain a 0/1 flag to see if
 					<attr> authentication is enabled.
 					This attribute is mandatory.
 
-		role:			The type of authentication used.
+		role:
+					The type of authentication used.
 					This attribute is mandatory.
+
 					Known types:
-						bios-admin: Representing BIOS administrator password
-						power-on: Representing a password required to use
-							  the system
+						bios-admin:
+							Representing BIOS administrator password
+						power-on:
+							Representing a password required to use
+							the system
 
-		mechanism:		The means of authentication.  This attribute is mandatory.
+		mechanism:
+					The means of authentication.  This attribute is mandatory.
 					Only supported type currently is "password".
 
-		max_password_length:	A file that can be read to obtain the
+		max_password_length:
+					A file that can be read to obtain the
 					maximum length of the Password
 
-		min_password_length:	A file that can be read to obtain the
+		min_password_length:
+					A file that can be read to obtain the
 					minimum length of the Password
 
-		current_password:	A write only value used for privileged access such as
+		current_password:
+					A write only value used for privileged access such as
 					setting	attributes when a system or admin password is set
 					or resetting to a new password
 
 					This attribute is mandatory when mechanism == "password".
 
-		new_password:		A write only value that when used in tandem with
+		new_password:
+					A write only value that when used in tandem with
 					current_password will reset a system or admin password.
 
 		Note, password management is session specific. If Admin password is set,
 		same password must be written into current_password file (required for
 		password-validation) and must be cleared once the session is over.
-		For example:
+		For example::
+
 			echo "password" > current_password
 			echo "disabled" > TouchScreen/current_value
 			echo "" > current_password
@@ -180,12 +211,15 @@ Description:
 		pending BIOS attribute changes. Also, an uevent_KOBJ_CHANGE is
 		generated when it changes to 1.
 
-			0:	All BIOS attributes setting are current
-			1:	A reboot is necessary to get pending BIOS attribute changes
-				applied
+			==	=========================================
+			0	All BIOS attributes setting are current
+			1	A reboot is necessary to get pending BIOS
+			        attribute changes applied
+			==	=========================================
 
 		Note, userspace applications need to follow below steps for efficient
 		BIOS management,
+
 		1.	Check if admin password is set. If yes, follow session method for
 			password management as briefed under authentication section above.
 		2.	Before setting any attribute, check if it has any modifiers
@@ -208,17 +242,17 @@ Description:
 
 		Reading from it returns a list of supported options encoded as:
 
-			'builtinsafe' (Built in safe configuration profile)
-			'lastknowngood' (Last known good saved configuration profile)
-			'factory' (Default factory settings configuration profile)
-			'custom' (Custom saved configuration profile)
+			- 'builtinsafe' (Built in safe configuration profile)
+			- 'lastknowngood' (Last known good saved configuration profile)
+			- 'factory' (Default factory settings configuration profile)
+			- 'custom' (Custom saved configuration profile)
 
 		The currently selected option is printed in square brackets as
-		shown below:
+		shown below::
 
-		# echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
-		# cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
-		# builtinsafe lastknowngood [factory] custom
+		    # echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
+		    # cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
+		    # builtinsafe lastknowngood [factory] custom
 
 		Note that any changes to this attribute requires a reboot
 		for changes to take effect.
-- 
2.26.2


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

* Re: [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems
  2020-10-29  8:01 ` Mauro Carvalho Chehab
  2020-10-29  9:31   ` [PATCH] docs: ABI: sysfs-class-firmware-attributes: solve some warnings Mauro Carvalho Chehab
@ 2020-10-29 10:03   ` Mauro Carvalho Chehab
  1 sibling, 0 replies; 6+ messages in thread
From: Mauro Carvalho Chehab @ 2020-10-29 10:03 UTC (permalink / raw)
  To: Divya Bharathi
  Cc: dvhart, LKML, platform-driver-x86, Divya Bharathi, Hans de Goede,
	Andy Shevchenko, mark gross, Mario Limonciello, Prasanth KSR,
	Greg Kroah-Hartman, Linux Doc Mailing List

Em Thu, 29 Oct 2020 09:01:14 +0100
Mauro Carvalho Chehab <mchehab+huawei@kernel.org> escreveu:

> Em Tue, 27 Oct 2020 19:19:44 +0530
> Divya Bharathi <divya27392@gmail.com> escreveu:
> 
> > The Dell WMI Systems Management Driver provides a sysfs
> > interface for systems management to enable BIOS configuration
> > capability on certain Dell Systems.
> > 
> > This driver allows user to configure Dell systems with a
> > uniform common interface. To facilitate this, the patch
> > introduces a generic way for driver to be able to create
> > configurable BIOS Attributes available in Setup (F2) screen.
> > 
> > Cc: Hans de Goede <hdegoede@redhat.com>
> > Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
> > Cc: mark gross <mgross@linux.intel.com>
> > 
> > Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
> > Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> > Co-developed-by: Prasanth KSR <prasanth.ksr@dell.com>
> > Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
> > Signed-off-by: Divya Bharathi <divya.bharathi@dell.com>
> > ---  
> 
> 
> > +What:		/sys/class/firmware-attributes/*/authentication/
> > +Date:		February 2021
> > +KernelVersion:	5.11
> > +Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
> > +		Mario Limonciello <mario.limonciello@dell.com>,
> > +		Prasanth KSR <prasanth.ksr@dell.com>
> > +
> > +		Devices support various authentication mechanisms which can be exposed
> > +		as a separate configuration object.
> > +
> > +		For example a "BIOS Admin" password and "System" Password can be set,
> > +		reset or cleared using these attributes.
> > +		- An "Admin" password is used for preventing modification to the BIOS
> > +		  settings.
> > +		- A "System" password is required to boot a machine.
> > +  
> 
> This is adding a new warning:
> 
> 	$ ./scripts/get_abi.pl validate
> 	Warning: file Documentation/ABI/testing/sysfs-class-firmware-attributes#172:
> 		What '/sys/class/firmware-attributes/*/authentication/' doesn't have a description
> 
> Because you forgot to add a Description: tag.
> 
> Feel free to either add the enclosed tag to the tree which added this into
> linux-next, or to fold id with the original patch.
> 
> Thanks,
> Mauro
> 
> ABI: docs: sysfs-class-firmware-attributes: add a missing tag
>     
> The Description:  tag is missing, causing this warning with
> scripts/get_abi.pl:
>     
> 	Warning: file Documentation/ABI/testing/sysfs-class-firmware-attributes#172:
> 		 What '/sys/class/firmware-attributes/*/authentication/' doesn't have a description
>     
> Fixes: e8a60aa7404b ("platform/x86: Introduce support for Systems Management Driver over WMI for Dell Systems")
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> index 04a15c72e883..ea1837f1f3c2 100644
> --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
> +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> @@ -113,7 +113,7 @@ KernelVersion:	5.11
>  Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
>  		Mario Limonciello <mario.limonciello@dell.com>,
>  		Prasanth KSR <prasanth.ksr@dell.com>
> -
> +Description:
>  		Devices support various authentication mechanisms which can be exposed
>  		as a separate configuration object.
>  
> 

There are a few other warnings produced by it, when generating the
ABI output, so, I sent a new patch covering all warnings.

If you want to test the ABI file generation, the patchset is at:

	https://git.linuxtv.org/mchehab/experimental.git/log/?h=abi_patches_v7

You can easily build just the sysfs firmware attribute class ABI with
something like this:

	$ mkdir -p fodir && cp Documentation/ABI/testing/sysfs-class-firmware-attributes fodir/ && ./scripts/get_abi.pl rest -dir fodir/ --rst-source >Documentation/foo/abi.rst && make SPHINXDIRS=foo htmldocs

You can also see it at:

	http://www.infradead.org/~mchehab/kernel_docs/foo/abi.html


Thanks,
Mauro

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

* Re: [PATCH] docs: ABI: sysfs-class-firmware-attributes: solve some warnings
  2020-10-29  9:31   ` [PATCH] docs: ABI: sysfs-class-firmware-attributes: solve some warnings Mauro Carvalho Chehab
@ 2020-11-03  9:35     ` Hans de Goede
  0 siblings, 0 replies; 6+ messages in thread
From: Hans de Goede @ 2020-11-03  9:35 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Linux Doc Mailing List, Divya Bharathi
  Cc: Andy Shevchenko, Divya Bharathi, Greg Kroah-Hartman,
	Jonathan Corbet, LKML, Mario Limonciello, Prasanth KSR,
	mark gross, dvhart, platform-driver-x86

Hi,

On 10/29/20 10:31 AM, Mauro Carvalho Chehab wrote:
> The Description: tag is missing on some places, causing
> scripts/get_abi.pl warnings:
> 
> 	Warning: file Documentation/ABI/testing/sysfs-class-firmware-attributes#172:
> 		What '/sys/class/firmware-attributes/*/authentication/' doesn't have a description
> 
> Also, some warnings are produced when generating html documentation:
> 
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Title underline too short.
> 
> 	Dell specific class extensions
> 	--------------------------
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Unexpected indentation.
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Unexpected indentation.
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:2: WARNING: Block quote ends without a blank line; unexpected unindent.
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:173: WARNING: Unexpected indentation.
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:173: WARNING: Unexpected indentation.
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:173: WARNING: Block quote ends without a blank line; unexpected unindent.
> 	.../Documentation/ABI/testing/sysfs-class-firmware-attributes:111: WARNING: Inline emphasis start-string without end-string.
> 
> Address the warnings, making it to produce the expected
> output for the documentation ABI.
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

Thank you for your patch, I've applied this patch to my review-hans 
branch:
https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans

Note it will show up in my review-hans branch once I've pushed my
local branch there, which might take a while.

Once I've run some tests on this branch the patches there will be
added to the platform-drivers-x86/for-next branch and eventually
will be included in the pdx86 pull-request to Linus for the next
merge-window.

Regards,

Hans


> ---
>  .../testing/sysfs-class-firmware-attributes   | 138 +++++++++++-------
>  1 file changed, 86 insertions(+), 52 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> index 04a15c72e883..8ea59fea4709 100644
> --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
> +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> @@ -12,17 +12,20 @@ Description:
>  		Unless otherwise specified in an attribute description all attributes are optional
>  		and will accept UTF-8 input.
>  
> -		type: A file that can be read to obtain the type of attribute.  This attribute is
> -			mandatory.
> +		type:
> +		    A file that can be read to obtain the type of attribute.
> +		    This attribute is mandatory.
>  
>  		The following are known types:
> +
>  			- enumeration: a set of pre-defined valid values
>  			- integer: a range of numerical values
>  			- string
>  
>  		All attribute types support the following values:
>  
> -		current_value:	A file that can be read to obtain the current
> +		current_value:
> +				A file that can be read to obtain the current
>  				value of the <attr>.
>  
>  				This file can also be written to in order to update the value of a
> @@ -30,59 +33,71 @@ Description:
>  
>  				This attribute is mandatory.
>  
> -		default_value:	A file that can be read to obtain the default
> +		default_value:
> +				A file that can be read to obtain the default
>  				value of the <attr>
>  
> -		display_name:	A file that can be read to obtain a user friendly
> +		display_name:
> +				A file that can be read to obtain a user friendly
>  				description of the at <attr>
>  
> -		display_name_language_code:	A file that can be read to obtain
> +		display_name_language_code:
> +						A file that can be read to obtain
>  						the IETF language tag corresponding to the
>  						"display_name" of the <attr>
>  
>  		"enumeration"-type specific properties:
>  
> -		possible_values:	A file that can be read to obtain the possible
> +		possible_values:
> +					A file that can be read to obtain the possible
>  					values of the <attr>. Values are separated using
>  					semi-colon (``;``).
>  
>  		"integer"-type specific properties:
>  
> -		min_value:	A file that can be read to obtain the lower
> +		min_value:
> +				A file that can be read to obtain the lower
>  				bound value of the <attr>
>  
> -		max_value:	A file that can be read to obtain the upper
> +		max_value:
> +				A file that can be read to obtain the upper
>  				bound value of the <attr>
>  
> -		scalar_increment:	A file that can be read to obtain the scalar value used for
> +		scalar_increment:
> +					A file that can be read to obtain the scalar value used for
>  					increments of current_value this attribute accepts.
>  
>  		"string"-type specific properties:
>  
> -		max_length:	A file that can be read to obtain the maximum
> +		max_length:
> +				A file that can be read to obtain the maximum
>  				length value of the <attr>
>  
> -		min_length:	A file that can be read to obtain the minimum
> +		min_length:
> +				A file that can be read to obtain the minimum
>  				length value of the <attr>
>  
>  		Dell specific class extensions
> -		--------------------------
> +		------------------------------
>  
>  		On Dell systems the following additional attributes are available:
>  
> -		dell_modifier:	A file that can be read to obtain attribute-level
> +		dell_modifier:
> +				A file that can be read to obtain attribute-level
>  				dependency rule. It says an attribute X will become read-only or
>  				suppressed, if/if-not attribute Y is configured.
>  
> -				modifier rules can be in following format:
> -				[ReadOnlyIf:<attribute>=<value>]
> -				[ReadOnlyIfNot:<attribute>=<value>]
> -				[SuppressIf:<attribute>=<value>]
> -				[SuppressIfNot:<attribute>=<value>]
> +				modifier rules can be in following format::
>  
> -				For example:
> -				AutoOnFri/dell_modifier has value,
> -					[SuppressIfNot:AutoOn=SelectDays]
> +				    [ReadOnlyIf:<attribute>=<value>]
> +				    [ReadOnlyIfNot:<attribute>=<value>]
> +				    [SuppressIf:<attribute>=<value>]
> +				    [SuppressIfNot:<attribute>=<value>]
> +
> +				For example::
> +
> +				    AutoOnFri/dell_modifier has value,
> +					    [SuppressIfNot:AutoOn=SelectDays]
>  
>  				This means AutoOnFri will be suppressed in BIOS setup if AutoOn
>  				attribute is not "SelectDays" and its value will not be effective
> @@ -90,18 +105,22 @@ Description:
>  
>  		Enumeration attributes also support the following:
>  
> -		dell_value_modifier:	A file that can be read to obtain value-level dependency.
> +		dell_value_modifier:
> +					A file that can be read to obtain value-level dependency.
>  					This file is similar to dell_modifier but here,	an
>  					attribute's current value will be forcefully changed based
>  					dependent attributes value.
>  
> -					dell_value_modifier rules can be in following format:
> -					<value>[ForceIf:<attribute>=<value>]
> -					<value>[ForceIfNot:<attribute>=<value>]
> +					dell_value_modifier rules can be in following format::
> +
> +					    <value>[ForceIf:<attribute>=<value>]
> +					    <value>[ForceIfNot:<attribute>=<value>]
> +
> +					For example:
> +
> +					    LegacyOrom/dell_value_modifier has value:
> +						    Disabled[ForceIf:SecureBoot=Enabled]
>  
> -					For example,
> -					LegacyOrom/dell_value_modifier has value:
> -						Disabled[ForceIf:SecureBoot=Enabled]
>  					This means LegacyOrom's current value will be forced to
>  					"Disabled" in BIOS setup if SecureBoot is Enabled and its
>  					value will not be effective through sysfs until this rule is
> @@ -113,12 +132,13 @@ KernelVersion:	5.11
>  Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
>  		Mario Limonciello <mario.limonciello@dell.com>,
>  		Prasanth KSR <prasanth.ksr@dell.com>
> -
> +Description:
>  		Devices support various authentication mechanisms which can be exposed
>  		as a separate configuration object.
>  
>  		For example a "BIOS Admin" password and "System" Password can be set,
>  		reset or cleared using these attributes.
> +
>  		- An "Admin" password is used for preventing modification to the BIOS
>  		  settings.
>  		- A "System" password is required to boot a machine.
> @@ -126,39 +146,50 @@ Contact:	Divya Bharathi <Divya.Bharathi@Dell.com>,
>  		Change in any of these two authentication methods will also generate an
>  		uevent KOBJ_CHANGE.
>  
> -		is_enabled:		A file that can be read to obtain a 0/1 flag to see if
> +		is_enabled:
> +					A file that can be read to obtain a 0/1 flag to see if
>  					<attr> authentication is enabled.
>  					This attribute is mandatory.
>  
> -		role:			The type of authentication used.
> +		role:
> +					The type of authentication used.
>  					This attribute is mandatory.
> +
>  					Known types:
> -						bios-admin: Representing BIOS administrator password
> -						power-on: Representing a password required to use
> -							  the system
> +						bios-admin:
> +							Representing BIOS administrator password
> +						power-on:
> +							Representing a password required to use
> +							the system
>  
> -		mechanism:		The means of authentication.  This attribute is mandatory.
> +		mechanism:
> +					The means of authentication.  This attribute is mandatory.
>  					Only supported type currently is "password".
>  
> -		max_password_length:	A file that can be read to obtain the
> +		max_password_length:
> +					A file that can be read to obtain the
>  					maximum length of the Password
>  
> -		min_password_length:	A file that can be read to obtain the
> +		min_password_length:
> +					A file that can be read to obtain the
>  					minimum length of the Password
>  
> -		current_password:	A write only value used for privileged access such as
> +		current_password:
> +					A write only value used for privileged access such as
>  					setting	attributes when a system or admin password is set
>  					or resetting to a new password
>  
>  					This attribute is mandatory when mechanism == "password".
>  
> -		new_password:		A write only value that when used in tandem with
> +		new_password:
> +					A write only value that when used in tandem with
>  					current_password will reset a system or admin password.
>  
>  		Note, password management is session specific. If Admin password is set,
>  		same password must be written into current_password file (required for
>  		password-validation) and must be cleared once the session is over.
> -		For example:
> +		For example::
> +
>  			echo "password" > current_password
>  			echo "disabled" > TouchScreen/current_value
>  			echo "" > current_password
> @@ -180,12 +211,15 @@ Description:
>  		pending BIOS attribute changes. Also, an uevent_KOBJ_CHANGE is
>  		generated when it changes to 1.
>  
> -			0:	All BIOS attributes setting are current
> -			1:	A reboot is necessary to get pending BIOS attribute changes
> -				applied
> +			==	=========================================
> +			0	All BIOS attributes setting are current
> +			1	A reboot is necessary to get pending BIOS
> +			        attribute changes applied
> +			==	=========================================
>  
>  		Note, userspace applications need to follow below steps for efficient
>  		BIOS management,
> +
>  		1.	Check if admin password is set. If yes, follow session method for
>  			password management as briefed under authentication section above.
>  		2.	Before setting any attribute, check if it has any modifiers
> @@ -208,17 +242,17 @@ Description:
>  
>  		Reading from it returns a list of supported options encoded as:
>  
> -			'builtinsafe' (Built in safe configuration profile)
> -			'lastknowngood' (Last known good saved configuration profile)
> -			'factory' (Default factory settings configuration profile)
> -			'custom' (Custom saved configuration profile)
> +			- 'builtinsafe' (Built in safe configuration profile)
> +			- 'lastknowngood' (Last known good saved configuration profile)
> +			- 'factory' (Default factory settings configuration profile)
> +			- 'custom' (Custom saved configuration profile)
>  
>  		The currently selected option is printed in square brackets as
> -		shown below:
> +		shown below::
>  
> -		# echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
> -		# cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
> -		# builtinsafe lastknowngood [factory] custom
> +		    # echo "factory" > /sys/class/firmware-attributes/*/device/attributes/reset_bios
> +		    # cat /sys/class/firmware-attributes/*/device/attributes/reset_bios
> +		    # builtinsafe lastknowngood [factory] custom
>  
>  		Note that any changes to this attribute requires a reboot
>  		for changes to take effect.
> 


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

end of thread, other threads:[~2020-11-03  9:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-27 13:49 [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems Divya Bharathi
2020-10-28  9:57 ` Hans de Goede
2020-10-29  8:01 ` Mauro Carvalho Chehab
2020-10-29  9:31   ` [PATCH] docs: ABI: sysfs-class-firmware-attributes: solve some warnings Mauro Carvalho Chehab
2020-11-03  9:35     ` Hans de Goede
2020-10-29 10:03   ` [PATCH v7] Introduce support for Systems Management Driver over WMI for Dell Systems Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).