summaryrefslogtreecommitdiff
path: root/drivers/platform/x86/dell-smbios.c
diff options
context:
space:
mode:
authorMario Limonciello <mario.limonciello@dell.com>2017-11-01 14:25:31 -0500
committerDarren Hart (VMware) <dvhart@infradead.org>2017-11-03 16:33:59 -0700
commit549b4930f057658dc50d8010e66219233119a4d8 (patch)
tree4e7133caa1761a4f56555a341a09ce516a74957d /drivers/platform/x86/dell-smbios.c
parent33b9ca1e53b45f7cacdba9d4fba5cb1387b26827 (diff)
platform/x86: dell-smbios: Introduce dispatcher for SMM calls
This splits up the dell-smbios driver into two drivers: * dell-smbios * dell-smbios-smm dell-smbios can operate with multiple different dispatcher drivers to perform SMBIOS operations. Also modify the interface that dell-laptop and dell-wmi use align to this model more closely. Rather than a single global buffer being allocated for all drivers, each driver will allocate and be responsible for it's own buffer. The pointer will be passed to the calling function and each dispatcher driver will then internally copy it to the proper location to perform it's call. Add defines for calls used by these methods in the dell-smbios.h header for tracking purposes. Signed-off-by: Mario Limonciello <mario.limonciello@dell.com> Reviewed-by: Edward O'Callaghan <quasisec@google.com> Signed-off-by: Darren Hart (VMware) <dvhart@infradead.org>
Diffstat (limited to 'drivers/platform/x86/dell-smbios.c')
-rw-r--r--drivers/platform/x86/dell-smbios.c121
1 files changed, 64 insertions, 57 deletions
diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c
index ed4995fdcd46..2229d44cb92c 100644
--- a/drivers/platform/x86/dell-smbios.c
+++ b/drivers/platform/x86/dell-smbios.c
@@ -19,33 +19,26 @@
#include <linux/capability.h>
#include <linux/dmi.h>
#include <linux/err.h>
-#include <linux/gfp.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/io.h>
-#include "../../firmware/dcdbas.h"
#include "dell-smbios.h"
-struct calling_interface_structure {
- struct dmi_header header;
- u16 cmdIOAddress;
- u8 cmdIOCode;
- u32 supportedCmds;
- struct calling_interface_token tokens[];
-} __packed;
-
-static struct calling_interface_buffer *buffer;
-static DEFINE_MUTEX(buffer_mutex);
-
-static int da_command_address;
-static int da_command_code;
static int da_num_tokens;
static struct platform_device *platform_device;
static struct calling_interface_token *da_tokens;
static struct device_attribute *token_location_attrs;
static struct device_attribute *token_value_attrs;
static struct attribute **token_attrs;
+static DEFINE_MUTEX(smbios_mutex);
+
+struct smbios_device {
+ struct list_head list;
+ struct device *device;
+ int (*call_fn)(struct calling_interface_buffer *);
+};
+
+static LIST_HEAD(smbios_device_list);
int dell_smbios_error(int value)
{
@@ -62,42 +55,71 @@ int dell_smbios_error(int value)
}
EXPORT_SYMBOL_GPL(dell_smbios_error);
-struct calling_interface_buffer *dell_smbios_get_buffer(void)
+int dell_smbios_register_device(struct device *d, void *call_fn)
{
- mutex_lock(&buffer_mutex);
- dell_smbios_clear_buffer();
- return buffer;
-}
-EXPORT_SYMBOL_GPL(dell_smbios_get_buffer);
+ struct smbios_device *priv;
-void dell_smbios_clear_buffer(void)
-{
- memset(buffer, 0, sizeof(struct calling_interface_buffer));
+ priv = devm_kzalloc(d, sizeof(struct smbios_device), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ get_device(d);
+ priv->device = d;
+ priv->call_fn = call_fn;
+ mutex_lock(&smbios_mutex);
+ list_add_tail(&priv->list, &smbios_device_list);
+ mutex_unlock(&smbios_mutex);
+ dev_dbg(d, "Added device: %s\n", d->driver->name);
+ return 0;
}
-EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer);
+EXPORT_SYMBOL_GPL(dell_smbios_register_device);
-void dell_smbios_release_buffer(void)
+void dell_smbios_unregister_device(struct device *d)
{
- mutex_unlock(&buffer_mutex);
+ struct smbios_device *priv;
+
+ mutex_lock(&smbios_mutex);
+ list_for_each_entry(priv, &smbios_device_list, list) {
+ if (priv->device == d) {
+ list_del(&priv->list);
+ put_device(d);
+ break;
+ }
+ }
+ mutex_unlock(&smbios_mutex);
+ dev_dbg(d, "Remove device: %s\n", d->driver->name);
}
-EXPORT_SYMBOL_GPL(dell_smbios_release_buffer);
+EXPORT_SYMBOL_GPL(dell_smbios_unregister_device);
-void dell_smbios_send_request(int class, int select)
+int dell_smbios_call(struct calling_interface_buffer *buffer)
{
- struct smi_cmd command;
+ int (*call_fn)(struct calling_interface_buffer *) = NULL;
+ struct device *selected_dev = NULL;
+ struct smbios_device *priv;
+ int ret;
+
+ mutex_lock(&smbios_mutex);
+ list_for_each_entry(priv, &smbios_device_list, list) {
+ if (!selected_dev || priv->device->id >= selected_dev->id) {
+ dev_dbg(priv->device, "Trying device ID: %d\n",
+ priv->device->id);
+ call_fn = priv->call_fn;
+ selected_dev = priv->device;
+ }
+ }
- command.magic = SMI_CMD_MAGIC;
- command.command_address = da_command_address;
- command.command_code = da_command_code;
- command.ebx = virt_to_phys(buffer);
- command.ecx = 0x42534931;
+ if (!selected_dev) {
+ ret = -ENODEV;
+ pr_err("No dell-smbios drivers are loaded\n");
+ goto out_smbios_call;
+ }
- buffer->cmd_class = class;
- buffer->cmd_select = select;
+ ret = call_fn(buffer);
- dcdbas_smi_request(&command);
+out_smbios_call:
+ mutex_unlock(&smbios_mutex);
+ return ret;
}
-EXPORT_SYMBOL_GPL(dell_smbios_send_request);
+EXPORT_SYMBOL_GPL(dell_smbios_call);
struct calling_interface_token *dell_smbios_find_token(int tokenid)
{
@@ -146,9 +168,6 @@ static void __init parse_da_table(const struct dmi_header *dm)
if (dm->length < 17)
return;
- da_command_address = table->cmdIOAddress;
- da_command_code = table->cmdIOCode;
-
new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) *
sizeof(struct calling_interface_token),
GFP_KERNEL);
@@ -344,7 +363,6 @@ static void free_group(struct platform_device *pdev)
kfree(token_location_attrs);
}
-
static int __init dell_smbios_init(void)
{
const struct dmi_device *valid;
@@ -363,15 +381,6 @@ static int __init dell_smbios_init(void)
return -ENODEV;
}
- /*
- * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
- * is passed to SMI handler.
- */
- buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32);
- if (!buffer) {
- ret = -ENOMEM;
- goto fail_buffer;
- }
ret = platform_driver_register(&platform_driver);
if (ret)
goto fail_platform_driver;
@@ -404,22 +413,20 @@ fail_platform_device_alloc:
platform_driver_unregister(&platform_driver);
fail_platform_driver:
- free_page((unsigned long)buffer);
-
-fail_buffer:
kfree(da_tokens);
return ret;
}
static void __exit dell_smbios_exit(void)
{
+ mutex_lock(&smbios_mutex);
if (platform_device) {
free_group(platform_device);
platform_device_unregister(platform_device);
platform_driver_unregister(&platform_driver);
}
- free_page((unsigned long)buffer);
kfree(da_tokens);
+ mutex_unlock(&smbios_mutex);
}
subsys_initcall(dell_smbios_init);