From 2f9f26bd8614740b3c3b950394d945a99492a28e Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Fri, 22 Jan 2016 15:27:13 +0100 Subject: dell-laptop: extract SMBIOS-related code to a separate module Extract SMBIOS-related code from dell-laptop to a new kernel module, dell-smbios. The static specifier is removed from exported symbols, otherwise code is just moved around. Signed-off-by: Michał Kępień Reviewed-by: Pali Rohár [dvhart: Include linux/io.h in dell-smbios.c as caught by lkp] Signed-off-by: Darren Hart --- drivers/platform/x86/dell-smbios.c | 194 +++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 drivers/platform/x86/dell-smbios.c (limited to 'drivers/platform/x86/dell-smbios.c') diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c new file mode 100644 index 000000000000..d1aae53dc7a7 --- /dev/null +++ b/drivers/platform/x86/dell-smbios.c @@ -0,0 +1,194 @@ +/* + * Common functions for kernel modules using Dell SMBIOS + * + * Copyright (c) Red Hat + * Copyright (c) 2014 Gabriele Mazzotta + * Copyright (c) 2014 Pali Rohár + * + * Based on documentation in the libsmbios package: + * Copyright (C) 2005-2014 Dell Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#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; + +struct calling_interface_buffer *buffer; +EXPORT_SYMBOL_GPL(buffer); +static DEFINE_MUTEX(buffer_mutex); + +static int da_command_address; +static int da_command_code; +static int da_num_tokens; +struct calling_interface_token *da_tokens; +EXPORT_SYMBOL_GPL(da_tokens); + +void get_buffer(void) +{ + mutex_lock(&buffer_mutex); + clear_buffer(); +} +EXPORT_SYMBOL_GPL(get_buffer); + +void clear_buffer(void) +{ + memset(buffer, 0, sizeof(struct calling_interface_buffer)); +} +EXPORT_SYMBOL_GPL(clear_buffer); + +void release_buffer(void) +{ + mutex_unlock(&buffer_mutex); +} +EXPORT_SYMBOL_GPL(release_buffer); + +struct calling_interface_buffer * +dell_send_request(struct calling_interface_buffer *buffer, + int class, int select) +{ + struct smi_cmd command; + + 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; + + buffer->class = class; + buffer->select = select; + + dcdbas_smi_request(&command); + + return buffer; +} +EXPORT_SYMBOL_GPL(dell_send_request); + +int find_token_id(int tokenid) +{ + int i; + + for (i = 0; i < da_num_tokens; i++) { + if (da_tokens[i].tokenID == tokenid) + return i; + } + + return -1; +} +EXPORT_SYMBOL_GPL(find_token_id); + +int find_token_location(int tokenid) +{ + int id; + + id = find_token_id(tokenid); + if (id == -1) + return -1; + + return da_tokens[id].location; +} +EXPORT_SYMBOL_GPL(find_token_location); + +static void __init parse_da_table(const struct dmi_header *dm) +{ + /* Final token is a terminator, so we don't want to copy it */ + int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; + struct calling_interface_token *new_da_tokens; + struct calling_interface_structure *table = + container_of(dm, struct calling_interface_structure, header); + + /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least + 6 bytes of entry */ + + 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); + + if (!new_da_tokens) + return; + da_tokens = new_da_tokens; + + memcpy(da_tokens+da_num_tokens, table->tokens, + sizeof(struct calling_interface_token) * tokens); + + da_num_tokens += tokens; +} + +static void __init find_tokens(const struct dmi_header *dm, void *dummy) +{ + switch (dm->type) { + case 0xd4: /* Indexed IO */ + case 0xd5: /* Protected Area Type 1 */ + case 0xd6: /* Protected Area Type 2 */ + break; + case 0xda: /* Calling interface */ + parse_da_table(dm); + break; + } +} + +static int __init dell_smbios_init(void) +{ + int ret; + + dmi_walk(find_tokens, NULL); + + if (!da_tokens) { + pr_info("Unable to find dmi tokens\n"); + 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; + } + + return 0; + +fail_buffer: + kfree(da_tokens); + return ret; +} + +static void __exit dell_smbios_exit(void) +{ + kfree(da_tokens); + free_page((unsigned long)buffer); +} + +subsys_initcall(dell_smbios_init); +module_exit(dell_smbios_exit); + +MODULE_AUTHOR("Matthew Garrett "); +MODULE_AUTHOR("Gabriele Mazzotta "); +MODULE_AUTHOR("Pali Rohár "); +MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3