summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/dell/dcdbas.c127
-rw-r--r--drivers/platform/x86/dell/dcdbas.h9
-rw-r--r--drivers/platform/x86/dell/dell-smbios-smm.c14
3 files changed, 87 insertions, 63 deletions
diff --git a/drivers/platform/x86/dell/dcdbas.c b/drivers/platform/x86/dell/dcdbas.c
index db3633fafbd5..42beafbc54b2 100644
--- a/drivers/platform/x86/dell/dcdbas.c
+++ b/drivers/platform/x86/dell/dcdbas.c
@@ -40,13 +40,10 @@
static struct platform_device *dcdbas_pdev;
-static u8 *smi_data_buf;
-static dma_addr_t smi_data_buf_handle;
-static unsigned long smi_data_buf_size;
static unsigned long max_smi_data_buf_size = MAX_SMI_DATA_BUF_SIZE;
-static u32 smi_data_buf_phys_addr;
static DEFINE_MUTEX(smi_data_lock);
static u8 *bios_buffer;
+static struct smi_buffer smi_buf;
static unsigned int host_control_action;
static unsigned int host_control_smi_type;
@@ -54,23 +51,49 @@ static unsigned int host_control_on_shutdown;
static bool wsmt_enabled;
+int dcdbas_smi_alloc(struct smi_buffer *smi_buffer, unsigned long size)
+{
+ smi_buffer->virt = dma_alloc_coherent(&dcdbas_pdev->dev, size,
+ &smi_buffer->dma, GFP_KERNEL);
+ if (!smi_buffer->virt) {
+ dev_dbg(&dcdbas_pdev->dev,
+ "%s: failed to allocate memory size %lu\n",
+ __func__, size);
+ return -ENOMEM;
+ }
+ smi_buffer->size = size;
+
+ dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+ __func__, (u32)smi_buffer->dma, smi_buffer->size);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dcdbas_smi_alloc);
+
+void dcdbas_smi_free(struct smi_buffer *smi_buffer)
+{
+ if (!smi_buffer->virt)
+ return;
+
+ dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
+ __func__, (u32)smi_buffer->dma, smi_buffer->size);
+ dma_free_coherent(&dcdbas_pdev->dev, smi_buffer->size,
+ smi_buffer->virt, smi_buffer->dma);
+ smi_buffer->virt = NULL;
+ smi_buffer->dma = 0;
+ smi_buffer->size = 0;
+}
+EXPORT_SYMBOL_GPL(dcdbas_smi_free);
+
/**
* smi_data_buf_free: free SMI data buffer
*/
static void smi_data_buf_free(void)
{
- if (!smi_data_buf || wsmt_enabled)
+ if (!smi_buf.virt || wsmt_enabled)
return;
- dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
- __func__, smi_data_buf_phys_addr, smi_data_buf_size);
-
- dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf,
- smi_data_buf_handle);
- smi_data_buf = NULL;
- smi_data_buf_handle = 0;
- smi_data_buf_phys_addr = 0;
- smi_data_buf_size = 0;
+ dcdbas_smi_free(&smi_buf);
}
/**
@@ -78,39 +101,29 @@ static void smi_data_buf_free(void)
*/
static int smi_data_buf_realloc(unsigned long size)
{
- void *buf;
- dma_addr_t handle;
+ struct smi_buffer tmp;
+ int ret;
- if (smi_data_buf_size >= size)
+ if (smi_buf.size >= size)
return 0;
if (size > max_smi_data_buf_size)
return -EINVAL;
/* new buffer is needed */
- buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL);
- if (!buf) {
- dev_dbg(&dcdbas_pdev->dev,
- "%s: failed to allocate memory size %lu\n",
- __func__, size);
- return -ENOMEM;
- }
- /* memory zeroed by dma_alloc_coherent */
+ ret = dcdbas_smi_alloc(&tmp, size);
+ if (ret)
+ return ret;
- if (smi_data_buf)
- memcpy(buf, smi_data_buf, smi_data_buf_size);
+ /* memory zeroed by dma_alloc_coherent */
+ if (smi_buf.virt)
+ memcpy(tmp.virt, smi_buf.virt, smi_buf.size);
/* free any existing buffer */
smi_data_buf_free();
/* set up new buffer for use */
- smi_data_buf = buf;
- smi_data_buf_handle = handle;
- smi_data_buf_phys_addr = (u32) virt_to_phys(buf);
- smi_data_buf_size = size;
-
- dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
- __func__, smi_data_buf_phys_addr, smi_data_buf_size);
+ smi_buf = tmp;
return 0;
}
@@ -119,14 +132,14 @@ static ssize_t smi_data_buf_phys_addr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%x\n", smi_data_buf_phys_addr);
+ return sprintf(buf, "%x\n", (u32)smi_buf.dma);
}
static ssize_t smi_data_buf_size_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return sprintf(buf, "%lu\n", smi_data_buf_size);
+ return sprintf(buf, "%lu\n", smi_buf.size);
}
static ssize_t smi_data_buf_size_store(struct device *dev,
@@ -155,8 +168,8 @@ static ssize_t smi_data_read(struct file *filp, struct kobject *kobj,
ssize_t ret;
mutex_lock(&smi_data_lock);
- ret = memory_read_from_buffer(buf, count, &pos, smi_data_buf,
- smi_data_buf_size);
+ ret = memory_read_from_buffer(buf, count, &pos, smi_buf.virt,
+ smi_buf.size);
mutex_unlock(&smi_data_lock);
return ret;
}
@@ -176,7 +189,7 @@ static ssize_t smi_data_write(struct file *filp, struct kobject *kobj,
if (ret)
goto out;
- memcpy(smi_data_buf + pos, buf, count);
+ memcpy(smi_buf.virt + pos, buf, count);
ret = count;
out:
mutex_unlock(&smi_data_lock);
@@ -307,11 +320,11 @@ static ssize_t smi_request_store(struct device *dev,
mutex_lock(&smi_data_lock);
- if (smi_data_buf_size < sizeof(struct smi_cmd)) {
+ if (smi_buf.size < sizeof(struct smi_cmd)) {
ret = -ENODEV;
goto out;
}
- smi_cmd = (struct smi_cmd *)smi_data_buf;
+ smi_cmd = (struct smi_cmd *)smi_buf.virt;
switch (val) {
case 2:
@@ -327,20 +340,20 @@ static ssize_t smi_request_store(struct device *dev,
* Provide physical address of command buffer field within
* the struct smi_cmd to BIOS.
*
- * Because the address that smi_cmd (smi_data_buf) points to
+ * Because the address that smi_cmd (smi_buf.virt) points to
* will be from memremap() of a non-memory address if WSMT
* is present, we can't use virt_to_phys() on smi_cmd, so
* we have to use the physical address that was saved when
* the virtual address for smi_cmd was received.
*/
- smi_cmd->ebx = smi_data_buf_phys_addr +
+ smi_cmd->ebx = (u32)smi_buf.dma +
offsetof(struct smi_cmd, command_buffer);
ret = dcdbas_smi_request(smi_cmd);
if (!ret)
ret = count;
break;
case 0:
- memset(smi_data_buf, 0, smi_data_buf_size);
+ memset(smi_buf.virt, 0, smi_buf.size);
ret = count;
break;
default:
@@ -356,7 +369,7 @@ out:
/**
* host_control_smi: generate host control SMI
*
- * Caller must set up the host control command in smi_data_buf.
+ * Caller must set up the host control command in smi_buf.virt.
*/
static int host_control_smi(void)
{
@@ -367,14 +380,14 @@ static int host_control_smi(void)
s8 cmd_status;
u8 index;
- apm_cmd = (struct apm_cmd *)smi_data_buf;
+ apm_cmd = (struct apm_cmd *)smi_buf.virt;
apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL;
switch (host_control_smi_type) {
case HC_SMITYPE_TYPE1:
spin_lock_irqsave(&rtc_lock, flags);
/* write SMI data buffer physical address */
- data = (u8 *)&smi_data_buf_phys_addr;
+ data = (u8 *)&smi_buf.dma;
for (index = PE1300_CMOS_CMD_STRUCT_PTR;
index < (PE1300_CMOS_CMD_STRUCT_PTR + 4);
index++, data++) {
@@ -405,7 +418,7 @@ static int host_control_smi(void)
case HC_SMITYPE_TYPE3:
spin_lock_irqsave(&rtc_lock, flags);
/* write SMI data buffer physical address */
- data = (u8 *)&smi_data_buf_phys_addr;
+ data = (u8 *)&smi_buf.dma;
for (index = PE1400_CMOS_CMD_STRUCT_PTR;
index < (PE1400_CMOS_CMD_STRUCT_PTR + 4);
index++, data++) {
@@ -450,7 +463,7 @@ static int host_control_smi(void)
* This function is called by the driver after the system has
* finished shutting down if the user application specified a
* host control action to perform on shutdown. It is safe to
- * use smi_data_buf at this point because the system has finished
+ * use smi_buf.virt at this point because the system has finished
* shutting down and no userspace apps are running.
*/
static void dcdbas_host_control(void)
@@ -464,18 +477,18 @@ static void dcdbas_host_control(void)
action = host_control_action;
host_control_action = HC_ACTION_NONE;
- if (!smi_data_buf) {
+ if (!smi_buf.virt) {
dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__);
return;
}
- if (smi_data_buf_size < sizeof(struct apm_cmd)) {
+ if (smi_buf.size < sizeof(struct apm_cmd)) {
dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
__func__);
return;
}
- apm_cmd = (struct apm_cmd *)smi_data_buf;
+ apm_cmd = (struct apm_cmd *)smi_buf.virt;
/* power off takes precedence */
if (action & HC_ACTION_HOST_CONTROL_POWEROFF) {
@@ -583,11 +596,11 @@ remap:
return -ENOMEM;
}
- /* First 8 bytes is for a semaphore, not part of the smi_data_buf */
- smi_data_buf_phys_addr = bios_buf_paddr + 8;
- smi_data_buf = bios_buffer + 8;
- smi_data_buf_size = remap_size - 8;
- max_smi_data_buf_size = smi_data_buf_size;
+ /* First 8 bytes is for a semaphore, not part of the smi_buf.virt */
+ smi_buf.dma = bios_buf_paddr + 8;
+ smi_buf.virt = bios_buffer + 8;
+ smi_buf.size = remap_size - 8;
+ max_smi_data_buf_size = smi_buf.size;
wsmt_enabled = true;
dev_info(&dcdbas_pdev->dev,
"WSMT found, using firmware-provided SMI buffer.\n");
diff --git a/drivers/platform/x86/dell/dcdbas.h b/drivers/platform/x86/dell/dcdbas.h
index c3cca5433525..942a23ddded0 100644
--- a/drivers/platform/x86/dell/dcdbas.h
+++ b/drivers/platform/x86/dell/dcdbas.h
@@ -105,5 +105,14 @@ struct smm_eps_table {
u64 num_of_4k_pages;
} __packed;
+struct smi_buffer {
+ u8 *virt;
+ unsigned long size;
+ dma_addr_t dma;
+};
+
+int dcdbas_smi_alloc(struct smi_buffer *smi_buffer, unsigned long size);
+void dcdbas_smi_free(struct smi_buffer *smi_buffer);
+
#endif /* _DCDBAS_H_ */
diff --git a/drivers/platform/x86/dell/dell-smbios-smm.c b/drivers/platform/x86/dell/dell-smbios-smm.c
index 320c032418ac..4d375985c85f 100644
--- a/drivers/platform/x86/dell/dell-smbios-smm.c
+++ b/drivers/platform/x86/dell/dell-smbios-smm.c
@@ -20,6 +20,7 @@
static int da_command_address;
static int da_command_code;
+static struct smi_buffer smi_buf;
static struct calling_interface_buffer *buffer;
static struct platform_device *platform_device;
static DEFINE_MUTEX(smm_mutex);
@@ -57,7 +58,7 @@ static int dell_smbios_smm_call(struct calling_interface_buffer *input)
command.magic = SMI_CMD_MAGIC;
command.command_address = da_command_address;
command.command_code = da_command_code;
- command.ebx = virt_to_phys(buffer);
+ command.ebx = smi_buf.dma;
command.ecx = 0x42534931;
mutex_lock(&smm_mutex);
@@ -101,9 +102,10 @@ int init_dell_smbios_smm(void)
* 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)
- return -ENOMEM;
+ ret = dcdbas_smi_alloc(&smi_buf, PAGE_SIZE);
+ if (ret)
+ return ret;
+ buffer = (void *)smi_buf.virt;
dmi_walk(find_cmd_address, NULL);
@@ -138,7 +140,7 @@ fail_platform_device_add:
fail_wsmt:
fail_platform_device_alloc:
- free_page((unsigned long)buffer);
+ dcdbas_smi_free(&smi_buf);
return ret;
}
@@ -147,6 +149,6 @@ void exit_dell_smbios_smm(void)
if (platform_device) {
dell_smbios_unregister_device(&platform_device->dev);
platform_device_unregister(platform_device);
- free_page((unsigned long)buffer);
+ dcdbas_smi_free(&smi_buf);
}
}