summaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorStuart Hayes <stuart.w.hayes@gmail.com>2018-09-26 17:50:20 -0400
committerAndy Shevchenko <andriy.shevchenko@linux.intel.com>2018-09-27 05:18:15 -0400
commit8e5cddd1262cdee59257d554440cc9a80e5fcb7b (patch)
tree809911c93a623e70cc3bd09cee5e53f71345f63f /drivers/firmware
parentc48e2ffd717ca4a67b4938bb60d110b7eeed39c4 (diff)
firmware: dcdbas: Move dcdbas to drivers/platform/x86
Move dcdbas to the more appropriate directory drivers/platform/x86. Signed-off-by: Stuart Hayes <stuart.w.hayes@gmail.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/Kconfig16
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/dcdbas.c761
-rw-r--r--drivers/firmware/dcdbas.h117
4 files changed, 0 insertions, 895 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 02f39d20efce..6d0c28fd3bad 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -145,22 +145,6 @@ config EFI_PCDP
145 See DIG64_HCDPv20_042804.pdf available from 145 See DIG64_HCDPv20_042804.pdf available from
146 <http://www.dig64.org/specifications/> 146 <http://www.dig64.org/specifications/>
147 147
148config DCDBAS
149 tristate "Dell Systems Management Base Driver"
150 depends on X86
151 help
152 The Dell Systems Management Base Driver provides a sysfs interface
153 for systems management software to perform System Management
154 Interrupts (SMIs) and Host Control Actions (system power cycle or
155 power off after OS shutdown) on certain Dell systems.
156
157 See <file:Documentation/dcdbas.txt> for more details on the driver
158 and the Dell systems on which Dell systems management software makes
159 use of this driver.
160
161 Say Y or M here to enable the driver for use by Dell systems
162 management software such as Dell OpenManage.
163
164config DMIID 148config DMIID
165 bool "Export DMI identification via sysfs to userspace" 149 bool "Export DMI identification via sysfs to userspace"
166 depends on DMI 150 depends on DMI
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 61887ba9df1d..edda4206d8fc 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_DMI) += dmi_scan.o
11obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o 11obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
12obj-$(CONFIG_EDD) += edd.o 12obj-$(CONFIG_EDD) += edd.o
13obj-$(CONFIG_EFI_PCDP) += pcdp.o 13obj-$(CONFIG_EFI_PCDP) += pcdp.o
14obj-$(CONFIG_DCDBAS) += dcdbas.o
15obj-$(CONFIG_DMIID) += dmi-id.o 14obj-$(CONFIG_DMIID) += dmi-id.o
16obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o 15obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
17obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o 16obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
deleted file mode 100644
index ae28e48ff7dc..000000000000
--- a/drivers/firmware/dcdbas.c
+++ /dev/null
@@ -1,761 +0,0 @@
1/*
2 * dcdbas.c: Dell Systems Management Base Driver
3 *
4 * The Dell Systems Management Base Driver provides a sysfs interface for
5 * systems management software to perform System Management Interrupts (SMIs)
6 * and Host Control Actions (power cycle or power off after OS shutdown) on
7 * Dell systems.
8 *
9 * See Documentation/dcdbas.txt for more information.
10 *
11 * Copyright (C) 1995-2006 Dell Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License v2.0 as published by
15 * the Free Software Foundation.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 */
22
23#include <linux/platform_device.h>
24#include <linux/acpi.h>
25#include <linux/dma-mapping.h>
26#include <linux/errno.h>
27#include <linux/cpu.h>
28#include <linux/gfp.h>
29#include <linux/init.h>
30#include <linux/kernel.h>
31#include <linux/mc146818rtc.h>
32#include <linux/module.h>
33#include <linux/reboot.h>
34#include <linux/sched.h>
35#include <linux/smp.h>
36#include <linux/spinlock.h>
37#include <linux/string.h>
38#include <linux/types.h>
39#include <linux/mutex.h>
40#include <asm/io.h>
41
42#include "dcdbas.h"
43
44#define DRIVER_NAME "dcdbas"
45#define DRIVER_VERSION "5.6.0-3.3"
46#define DRIVER_DESCRIPTION "Dell Systems Management Base Driver"
47
48static struct platform_device *dcdbas_pdev;
49
50static u8 *smi_data_buf;
51static dma_addr_t smi_data_buf_handle;
52static unsigned long smi_data_buf_size;
53static unsigned long max_smi_data_buf_size = MAX_SMI_DATA_BUF_SIZE;
54static u32 smi_data_buf_phys_addr;
55static DEFINE_MUTEX(smi_data_lock);
56static u8 *eps_buffer;
57
58static unsigned int host_control_action;
59static unsigned int host_control_smi_type;
60static unsigned int host_control_on_shutdown;
61
62static bool wsmt_enabled;
63
64/**
65 * smi_data_buf_free: free SMI data buffer
66 */
67static void smi_data_buf_free(void)
68{
69 if (!smi_data_buf || wsmt_enabled)
70 return;
71
72 dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
73 __func__, smi_data_buf_phys_addr, smi_data_buf_size);
74
75 dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf,
76 smi_data_buf_handle);
77 smi_data_buf = NULL;
78 smi_data_buf_handle = 0;
79 smi_data_buf_phys_addr = 0;
80 smi_data_buf_size = 0;
81}
82
83/**
84 * smi_data_buf_realloc: grow SMI data buffer if needed
85 */
86static int smi_data_buf_realloc(unsigned long size)
87{
88 void *buf;
89 dma_addr_t handle;
90
91 if (smi_data_buf_size >= size)
92 return 0;
93
94 if (size > max_smi_data_buf_size)
95 return -EINVAL;
96
97 /* new buffer is needed */
98 buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL);
99 if (!buf) {
100 dev_dbg(&dcdbas_pdev->dev,
101 "%s: failed to allocate memory size %lu\n",
102 __func__, size);
103 return -ENOMEM;
104 }
105 /* memory zeroed by dma_alloc_coherent */
106
107 if (smi_data_buf)
108 memcpy(buf, smi_data_buf, smi_data_buf_size);
109
110 /* free any existing buffer */
111 smi_data_buf_free();
112
113 /* set up new buffer for use */
114 smi_data_buf = buf;
115 smi_data_buf_handle = handle;
116 smi_data_buf_phys_addr = (u32) virt_to_phys(buf);
117 smi_data_buf_size = size;
118
119 dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
120 __func__, smi_data_buf_phys_addr, smi_data_buf_size);
121
122 return 0;
123}
124
125static ssize_t smi_data_buf_phys_addr_show(struct device *dev,
126 struct device_attribute *attr,
127 char *buf)
128{
129 return sprintf(buf, "%x\n", smi_data_buf_phys_addr);
130}
131
132static ssize_t smi_data_buf_size_show(struct device *dev,
133 struct device_attribute *attr,
134 char *buf)
135{
136 return sprintf(buf, "%lu\n", smi_data_buf_size);
137}
138
139static ssize_t smi_data_buf_size_store(struct device *dev,
140 struct device_attribute *attr,
141 const char *buf, size_t count)
142{
143 unsigned long buf_size;
144 ssize_t ret;
145
146 buf_size = simple_strtoul(buf, NULL, 10);
147
148 /* make sure SMI data buffer is at least buf_size */
149 mutex_lock(&smi_data_lock);
150 ret = smi_data_buf_realloc(buf_size);
151 mutex_unlock(&smi_data_lock);
152 if (ret)
153 return ret;
154
155 return count;
156}
157
158static ssize_t smi_data_read(struct file *filp, struct kobject *kobj,
159 struct bin_attribute *bin_attr,
160 char *buf, loff_t pos, size_t count)
161{
162 ssize_t ret;
163
164 mutex_lock(&smi_data_lock);
165 ret = memory_read_from_buffer(buf, count, &pos, smi_data_buf,
166 smi_data_buf_size);
167 mutex_unlock(&smi_data_lock);
168 return ret;
169}
170
171static ssize_t smi_data_write(struct file *filp, struct kobject *kobj,
172 struct bin_attribute *bin_attr,
173 char *buf, loff_t pos, size_t count)
174{
175 ssize_t ret;
176
177 if ((pos + count) > max_smi_data_buf_size)
178 return -EINVAL;
179
180 mutex_lock(&smi_data_lock);
181
182 ret = smi_data_buf_realloc(pos + count);
183 if (ret)
184 goto out;
185
186 memcpy(smi_data_buf + pos, buf, count);
187 ret = count;
188out:
189 mutex_unlock(&smi_data_lock);
190 return ret;
191}
192
193static ssize_t host_control_action_show(struct device *dev,
194 struct device_attribute *attr,
195 char *buf)
196{
197 return sprintf(buf, "%u\n", host_control_action);
198}
199
200static ssize_t host_control_action_store(struct device *dev,
201 struct device_attribute *attr,
202 const char *buf, size_t count)
203{
204 ssize_t ret;
205
206 /* make sure buffer is available for host control command */
207 mutex_lock(&smi_data_lock);
208 ret = smi_data_buf_realloc(sizeof(struct apm_cmd));
209 mutex_unlock(&smi_data_lock);
210 if (ret)
211 return ret;
212
213 host_control_action = simple_strtoul(buf, NULL, 10);
214 return count;
215}
216
217static ssize_t host_control_smi_type_show(struct device *dev,
218 struct device_attribute *attr,
219 char *buf)
220{
221 return sprintf(buf, "%u\n", host_control_smi_type);
222}
223
224static ssize_t host_control_smi_type_store(struct device *dev,
225 struct device_attribute *attr,
226 const char *buf, size_t count)
227{
228 host_control_smi_type = simple_strtoul(buf, NULL, 10);
229 return count;
230}
231
232static ssize_t host_control_on_shutdown_show(struct device *dev,
233 struct device_attribute *attr,
234 char *buf)
235{
236 return sprintf(buf, "%u\n", host_control_on_shutdown);
237}
238
239static ssize_t host_control_on_shutdown_store(struct device *dev,
240 struct device_attribute *attr,
241 const char *buf, size_t count)
242{
243 host_control_on_shutdown = simple_strtoul(buf, NULL, 10);
244 return count;
245}
246
247static int raise_smi(void *par)
248{
249 struct smi_cmd *smi_cmd = par;
250
251 if (smp_processor_id() != 0) {
252 dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
253 __func__);
254 return -EBUSY;
255 }
256
257 /* generate SMI */
258 /* inb to force posted write through and make SMI happen now */
259 asm volatile (
260 "outb %b0,%w1\n"
261 "inb %w1"
262 : /* no output args */
263 : "a" (smi_cmd->command_code),
264 "d" (smi_cmd->command_address),
265 "b" (smi_cmd->ebx),
266 "c" (smi_cmd->ecx)
267 : "memory"
268 );
269
270 return 0;
271}
272/**
273 * dcdbas_smi_request: generate SMI request
274 *
275 * Called with smi_data_lock.
276 */
277int dcdbas_smi_request(struct smi_cmd *smi_cmd)
278{
279 int ret;
280
281 if (smi_cmd->magic != SMI_CMD_MAGIC) {
282 dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
283 __func__);
284 return -EBADR;
285 }
286
287 /* SMI requires CPU 0 */
288 get_online_cpus();
289 ret = smp_call_on_cpu(0, raise_smi, smi_cmd, true);
290 put_online_cpus();
291
292 return ret;
293}
294
295/**
296 * smi_request_store:
297 *
298 * The valid values are:
299 * 0: zero SMI data buffer
300 * 1: generate calling interface SMI
301 * 2: generate raw SMI
302 *
303 * User application writes smi_cmd to smi_data before telling driver
304 * to generate SMI.
305 */
306static ssize_t smi_request_store(struct device *dev,
307 struct device_attribute *attr,
308 const char *buf, size_t count)
309{
310 struct smi_cmd *smi_cmd;
311 unsigned long val = simple_strtoul(buf, NULL, 10);
312 ssize_t ret;
313
314 mutex_lock(&smi_data_lock);
315
316 if (smi_data_buf_size < sizeof(struct smi_cmd)) {
317 ret = -ENODEV;
318 goto out;
319 }
320 smi_cmd = (struct smi_cmd *)smi_data_buf;
321
322 switch (val) {
323 case 2:
324 /* Raw SMI */
325 ret = dcdbas_smi_request(smi_cmd);
326 if (!ret)
327 ret = count;
328 break;
329 case 1:
330 /*
331 * Calling Interface SMI
332 *
333 * Provide physical address of command buffer field within
334 * the struct smi_cmd to BIOS.
335 *
336 * Because the address that smi_cmd (smi_data_buf) points to
337 * will be from memremap() of a non-memory address if WSMT
338 * is present, we can't use virt_to_phys() on smi_cmd, so
339 * we have to use the physical address that was saved when
340 * the virtual address for smi_cmd was received.
341 */
342 smi_cmd->ebx = smi_data_buf_phys_addr +
343 offsetof(struct smi_cmd, command_buffer);
344 ret = dcdbas_smi_request(smi_cmd);
345 if (!ret)
346 ret = count;
347 break;
348 case 0:
349 memset(smi_data_buf, 0, smi_data_buf_size);
350 ret = count;
351 break;
352 default:
353 ret = -EINVAL;
354 break;
355 }
356
357out:
358 mutex_unlock(&smi_data_lock);
359 return ret;
360}
361EXPORT_SYMBOL(dcdbas_smi_request);
362
363/**
364 * host_control_smi: generate host control SMI
365 *
366 * Caller must set up the host control command in smi_data_buf.
367 */
368static int host_control_smi(void)
369{
370 struct apm_cmd *apm_cmd;
371 u8 *data;
372 unsigned long flags;
373 u32 num_ticks;
374 s8 cmd_status;
375 u8 index;
376
377 apm_cmd = (struct apm_cmd *)smi_data_buf;
378 apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL;
379
380 switch (host_control_smi_type) {
381 case HC_SMITYPE_TYPE1:
382 spin_lock_irqsave(&rtc_lock, flags);
383 /* write SMI data buffer physical address */
384 data = (u8 *)&smi_data_buf_phys_addr;
385 for (index = PE1300_CMOS_CMD_STRUCT_PTR;
386 index < (PE1300_CMOS_CMD_STRUCT_PTR + 4);
387 index++, data++) {
388 outb(index,
389 (CMOS_BASE_PORT + CMOS_PAGE2_INDEX_PORT_PIIX4));
390 outb(*data,
391 (CMOS_BASE_PORT + CMOS_PAGE2_DATA_PORT_PIIX4));
392 }
393
394 /* first set status to -1 as called by spec */
395 cmd_status = ESM_STATUS_CMD_UNSUCCESSFUL;
396 outb((u8) cmd_status, PCAT_APM_STATUS_PORT);
397
398 /* generate SMM call */
399 outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
400 spin_unlock_irqrestore(&rtc_lock, flags);
401
402 /* wait a few to see if it executed */
403 num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
404 while ((cmd_status = inb(PCAT_APM_STATUS_PORT))
405 == ESM_STATUS_CMD_UNSUCCESSFUL) {
406 num_ticks--;
407 if (num_ticks == EXPIRED_TIMER)
408 return -ETIME;
409 }
410 break;
411
412 case HC_SMITYPE_TYPE2:
413 case HC_SMITYPE_TYPE3:
414 spin_lock_irqsave(&rtc_lock, flags);
415 /* write SMI data buffer physical address */
416 data = (u8 *)&smi_data_buf_phys_addr;
417 for (index = PE1400_CMOS_CMD_STRUCT_PTR;
418 index < (PE1400_CMOS_CMD_STRUCT_PTR + 4);
419 index++, data++) {
420 outb(index, (CMOS_BASE_PORT + CMOS_PAGE1_INDEX_PORT));
421 outb(*data, (CMOS_BASE_PORT + CMOS_PAGE1_DATA_PORT));
422 }
423
424 /* generate SMM call */
425 if (host_control_smi_type == HC_SMITYPE_TYPE3)
426 outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
427 else
428 outb(ESM_APM_CMD, PE1400_APM_CONTROL_PORT);
429
430 /* restore RTC index pointer since it was written to above */
431 CMOS_READ(RTC_REG_C);
432 spin_unlock_irqrestore(&rtc_lock, flags);
433
434 /* read control port back to serialize write */
435 cmd_status = inb(PE1400_APM_CONTROL_PORT);
436
437 /* wait a few to see if it executed */
438 num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
439 while (apm_cmd->status == ESM_STATUS_CMD_UNSUCCESSFUL) {
440 num_ticks--;
441 if (num_ticks == EXPIRED_TIMER)
442 return -ETIME;
443 }
444 break;
445
446 default:
447 dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n",
448 __func__, host_control_smi_type);
449 return -ENOSYS;
450 }
451
452 return 0;
453}
454
455/**
456 * dcdbas_host_control: initiate host control
457 *
458 * This function is called by the driver after the system has
459 * finished shutting down if the user application specified a
460 * host control action to perform on shutdown. It is safe to
461 * use smi_data_buf at this point because the system has finished
462 * shutting down and no userspace apps are running.
463 */
464static void dcdbas_host_control(void)
465{
466 struct apm_cmd *apm_cmd;
467 u8 action;
468
469 if (host_control_action == HC_ACTION_NONE)
470 return;
471
472 action = host_control_action;
473 host_control_action = HC_ACTION_NONE;
474
475 if (!smi_data_buf) {
476 dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__);
477 return;
478 }
479
480 if (smi_data_buf_size < sizeof(struct apm_cmd)) {
481 dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
482 __func__);
483 return;
484 }
485
486 apm_cmd = (struct apm_cmd *)smi_data_buf;
487
488 /* power off takes precedence */
489 if (action & HC_ACTION_HOST_CONTROL_POWEROFF) {
490 apm_cmd->command = ESM_APM_POWER_CYCLE;
491 apm_cmd->reserved = 0;
492 *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 0;
493 host_control_smi();
494 } else if (action & HC_ACTION_HOST_CONTROL_POWERCYCLE) {
495 apm_cmd->command = ESM_APM_POWER_CYCLE;
496 apm_cmd->reserved = 0;
497 *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 20;
498 host_control_smi();
499 }
500}
501
502/* WSMT */
503
504static u8 checksum(u8 *buffer, u8 length)
505{
506 u8 sum = 0;
507 u8 *end = buffer + length;
508
509 while (buffer < end)
510 sum += *buffer++;
511 return sum;
512}
513
514static inline struct smm_eps_table *check_eps_table(u8 *addr)
515{
516 struct smm_eps_table *eps = (struct smm_eps_table *)addr;
517
518 if (strncmp(eps->smm_comm_buff_anchor, SMM_EPS_SIG, 4) != 0)
519 return NULL;
520
521 if (checksum(addr, eps->length) != 0)
522 return NULL;
523
524 return eps;
525}
526
527static int dcdbas_check_wsmt(void)
528{
529 struct acpi_table_wsmt *wsmt = NULL;
530 struct smm_eps_table *eps = NULL;
531 u64 remap_size;
532 u8 *addr;
533
534 acpi_get_table(ACPI_SIG_WSMT, 0, (struct acpi_table_header **)&wsmt);
535 if (!wsmt)
536 return 0;
537
538 /* Check if WSMT ACPI table shows that protection is enabled */
539 if (!(wsmt->protection_flags & ACPI_WSMT_FIXED_COMM_BUFFERS) ||
540 !(wsmt->protection_flags & ACPI_WSMT_COMM_BUFFER_NESTED_PTR_PROTECTION))
541 return 0;
542
543 /* Scan for EPS (entry point structure) */
544 for (addr = (u8 *)__va(0xf0000);
545 addr < (u8 *)__va(0x100000 - sizeof(struct smm_eps_table));
546 addr += 16) {
547 eps = check_eps_table(addr);
548 if (eps)
549 break;
550 }
551
552 if (!eps) {
553 dev_dbg(&dcdbas_pdev->dev, "found WSMT, but no EPS found\n");
554 return -ENODEV;
555 }
556
557 /*
558 * Get physical address of buffer and map to virtual address.
559 * Table gives size in 4K pages, regardless of actual system page size.
560 */
561 if (upper_32_bits(eps->smm_comm_buff_addr + 8)) {
562 dev_warn(&dcdbas_pdev->dev, "found WSMT, but EPS buffer address is above 4GB\n");
563 return -EINVAL;
564 }
565 /*
566 * Limit remap size to MAX_SMI_DATA_BUF_SIZE + 8 (since the first 8
567 * bytes are used for a semaphore, not the data buffer itself).
568 */
569 remap_size = eps->num_of_4k_pages * PAGE_SIZE;
570 if (remap_size > MAX_SMI_DATA_BUF_SIZE + 8)
571 remap_size = MAX_SMI_DATA_BUF_SIZE + 8;
572 eps_buffer = memremap(eps->smm_comm_buff_addr, remap_size, MEMREMAP_WB);
573 if (!eps_buffer) {
574 dev_warn(&dcdbas_pdev->dev, "found WSMT, but failed to map EPS buffer\n");
575 return -ENOMEM;
576 }
577
578 /* First 8 bytes is for a semaphore, not part of the smi_data_buf */
579 smi_data_buf_phys_addr = eps->smm_comm_buff_addr + 8;
580 smi_data_buf = eps_buffer + 8;
581 smi_data_buf_size = remap_size - 8;
582 max_smi_data_buf_size = smi_data_buf_size;
583 wsmt_enabled = true;
584 dev_info(&dcdbas_pdev->dev,
585 "WSMT found, using firmware-provided SMI buffer.\n");
586 return 1;
587}
588
589/**
590 * dcdbas_reboot_notify: handle reboot notification for host control
591 */
592static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
593 void *unused)
594{
595 switch (code) {
596 case SYS_DOWN:
597 case SYS_HALT:
598 case SYS_POWER_OFF:
599 if (host_control_on_shutdown) {
600 /* firmware is going to perform host control action */
601 printk(KERN_WARNING "Please wait for shutdown "
602 "action to complete...\n");
603 dcdbas_host_control();
604 }
605 break;
606 }
607
608 return NOTIFY_DONE;
609}
610
611static struct notifier_block dcdbas_reboot_nb = {
612 .notifier_call = dcdbas_reboot_notify,
613 .next = NULL,
614 .priority = INT_MIN
615};
616
617static DCDBAS_BIN_ATTR_RW(smi_data);
618
619static struct bin_attribute *dcdbas_bin_attrs[] = {
620 &bin_attr_smi_data,
621 NULL
622};
623
624static DCDBAS_DEV_ATTR_RW(smi_data_buf_size);
625static DCDBAS_DEV_ATTR_RO(smi_data_buf_phys_addr);
626static DCDBAS_DEV_ATTR_WO(smi_request);
627static DCDBAS_DEV_ATTR_RW(host_control_action);
628static DCDBAS_DEV_ATTR_RW(host_control_smi_type);
629static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown);
630
631static struct attribute *dcdbas_dev_attrs[] = {
632 &dev_attr_smi_data_buf_size.attr,
633 &dev_attr_smi_data_buf_phys_addr.attr,
634 &dev_attr_smi_request.attr,
635 &dev_attr_host_control_action.attr,
636 &dev_attr_host_control_smi_type.attr,
637 &dev_attr_host_control_on_shutdown.attr,
638 NULL
639};
640
641static const struct attribute_group dcdbas_attr_group = {
642 .attrs = dcdbas_dev_attrs,
643 .bin_attrs = dcdbas_bin_attrs,
644};
645
646static int dcdbas_probe(struct platform_device *dev)
647{
648 int error;
649
650 host_control_action = HC_ACTION_NONE;
651 host_control_smi_type = HC_SMITYPE_NONE;
652
653 dcdbas_pdev = dev;
654
655 /* Check if ACPI WSMT table specifies protected SMI buffer address */
656 error = dcdbas_check_wsmt();
657 if (error < 0)
658 return error;
659
660 /*
661 * BIOS SMI calls require buffer addresses be in 32-bit address space.
662 * This is done by setting the DMA mask below.
663 */
664 error = dma_set_coherent_mask(&dcdbas_pdev->dev, DMA_BIT_MASK(32));
665 if (error)
666 return error;
667
668 error = sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group);
669 if (error)
670 return error;
671
672 register_reboot_notifier(&dcdbas_reboot_nb);
673
674 dev_info(&dev->dev, "%s (version %s)\n",
675 DRIVER_DESCRIPTION, DRIVER_VERSION);
676
677 return 0;
678}
679
680static int dcdbas_remove(struct platform_device *dev)
681{
682 unregister_reboot_notifier(&dcdbas_reboot_nb);
683 sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
684
685 return 0;
686}
687
688static struct platform_driver dcdbas_driver = {
689 .driver = {
690 .name = DRIVER_NAME,
691 },
692 .probe = dcdbas_probe,
693 .remove = dcdbas_remove,
694};
695
696static const struct platform_device_info dcdbas_dev_info __initconst = {
697 .name = DRIVER_NAME,
698 .id = -1,
699 .dma_mask = DMA_BIT_MASK(32),
700};
701
702static struct platform_device *dcdbas_pdev_reg;
703
704/**
705 * dcdbas_init: initialize driver
706 */
707static int __init dcdbas_init(void)
708{
709 int error;
710
711 error = platform_driver_register(&dcdbas_driver);
712 if (error)
713 return error;
714
715 dcdbas_pdev_reg = platform_device_register_full(&dcdbas_dev_info);
716 if (IS_ERR(dcdbas_pdev_reg)) {
717 error = PTR_ERR(dcdbas_pdev_reg);
718 goto err_unregister_driver;
719 }
720
721 return 0;
722
723 err_unregister_driver:
724 platform_driver_unregister(&dcdbas_driver);
725 return error;
726}
727
728/**
729 * dcdbas_exit: perform driver cleanup
730 */
731static void __exit dcdbas_exit(void)
732{
733 /*
734 * make sure functions that use dcdbas_pdev are called
735 * before platform_device_unregister
736 */
737 unregister_reboot_notifier(&dcdbas_reboot_nb);
738
739 /*
740 * We have to free the buffer here instead of dcdbas_remove
741 * because only in module exit function we can be sure that
742 * all sysfs attributes belonging to this module have been
743 * released.
744 */
745 if (dcdbas_pdev)
746 smi_data_buf_free();
747 if (eps_buffer)
748 memunmap(eps_buffer);
749 platform_device_unregister(dcdbas_pdev_reg);
750 platform_driver_unregister(&dcdbas_driver);
751}
752
753subsys_initcall_sync(dcdbas_init);
754module_exit(dcdbas_exit);
755
756MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
757MODULE_VERSION(DRIVER_VERSION);
758MODULE_AUTHOR("Dell Inc.");
759MODULE_LICENSE("GPL");
760/* Any System or BIOS claiming to be by Dell */
761MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*");
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
deleted file mode 100644
index 52729a494b00..000000000000
--- a/drivers/firmware/dcdbas.h
+++ /dev/null
@@ -1,117 +0,0 @@
1/*
2 * dcdbas.h: Definitions for Dell Systems Management Base driver
3 *
4 * Copyright (C) 1995-2005 Dell Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License v2.0 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#ifndef _DCDBAS_H_
17#define _DCDBAS_H_
18
19#include <linux/device.h>
20#include <linux/sysfs.h>
21#include <linux/types.h>
22
23#define MAX_SMI_DATA_BUF_SIZE (256 * 1024)
24
25#define HC_ACTION_NONE (0)
26#define HC_ACTION_HOST_CONTROL_POWEROFF BIT(1)
27#define HC_ACTION_HOST_CONTROL_POWERCYCLE BIT(2)
28
29#define HC_SMITYPE_NONE (0)
30#define HC_SMITYPE_TYPE1 (1)
31#define HC_SMITYPE_TYPE2 (2)
32#define HC_SMITYPE_TYPE3 (3)
33
34#define ESM_APM_CMD (0x0A0)
35#define ESM_APM_POWER_CYCLE (0x10)
36#define ESM_STATUS_CMD_UNSUCCESSFUL (-1)
37
38#define CMOS_BASE_PORT (0x070)
39#define CMOS_PAGE1_INDEX_PORT (0)
40#define CMOS_PAGE1_DATA_PORT (1)
41#define CMOS_PAGE2_INDEX_PORT_PIIX4 (2)
42#define CMOS_PAGE2_DATA_PORT_PIIX4 (3)
43#define PE1400_APM_CONTROL_PORT (0x0B0)
44#define PCAT_APM_CONTROL_PORT (0x0B2)
45#define PCAT_APM_STATUS_PORT (0x0B3)
46#define PE1300_CMOS_CMD_STRUCT_PTR (0x38)
47#define PE1400_CMOS_CMD_STRUCT_PTR (0x70)
48
49#define MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN (14)
50#define MAX_SYSMGMT_LONGCMD_SGENTRY_NUM (16)
51
52#define TIMEOUT_USEC_SHORT_SEMA_BLOCKING (10000)
53#define EXPIRED_TIMER (0)
54
55#define SMI_CMD_MAGIC (0x534D4931)
56#define SMM_EPS_SIG "$SCB"
57
58#define DCDBAS_DEV_ATTR_RW(_name) \
59 DEVICE_ATTR(_name,0600,_name##_show,_name##_store);
60
61#define DCDBAS_DEV_ATTR_RO(_name) \
62 DEVICE_ATTR(_name,0400,_name##_show,NULL);
63
64#define DCDBAS_DEV_ATTR_WO(_name) \
65 DEVICE_ATTR(_name,0200,NULL,_name##_store);
66
67#define DCDBAS_BIN_ATTR_RW(_name) \
68struct bin_attribute bin_attr_##_name = { \
69 .attr = { .name = __stringify(_name), \
70 .mode = 0600 }, \
71 .read = _name##_read, \
72 .write = _name##_write, \
73}
74
75struct smi_cmd {
76 __u32 magic;
77 __u32 ebx;
78 __u32 ecx;
79 __u16 command_address;
80 __u8 command_code;
81 __u8 reserved;
82 __u8 command_buffer[1];
83} __attribute__ ((packed));
84
85struct apm_cmd {
86 __u8 command;
87 __s8 status;
88 __u16 reserved;
89 union {
90 struct {
91 __u8 parm[MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN];
92 } __attribute__ ((packed)) shortreq;
93
94 struct {
95 __u16 num_sg_entries;
96 struct {
97 __u32 size;
98 __u64 addr;
99 } __attribute__ ((packed))
100 sglist[MAX_SYSMGMT_LONGCMD_SGENTRY_NUM];
101 } __attribute__ ((packed)) longreq;
102 } __attribute__ ((packed)) parameters;
103} __attribute__ ((packed));
104
105int dcdbas_smi_request(struct smi_cmd *smi_cmd);
106
107struct smm_eps_table {
108 char smm_comm_buff_anchor[4];
109 u8 length;
110 u8 checksum;
111 u8 version;
112 u64 smm_comm_buff_addr;
113 u64 num_of_4k_pages;
114} __packed;
115
116#endif /* _DCDBAS_H_ */
117