aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-09-08 05:39:55 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-08 05:39:55 -0400
commitc324b44c34050cf2a9b58830e11c974806bd85d8 (patch)
tree3ac45a783221283925cd698334a8f5e7dd4c1df8 /drivers/firmware
parent2fcf522509cceea524b6e7ece8fd6759b682175a (diff)
parentcaf39e87cc1182f7dae84eefc43ca14d54c78ef9 (diff)
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/Kconfig27
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/dcdbas.c596
-rw-r--r--drivers/firmware/dcdbas.h107
-rw-r--r--drivers/firmware/dell_rbu.c634
5 files changed, 1366 insertions, 0 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 5b29c3b2a331..327b58e64875 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -58,4 +58,31 @@ config EFI_PCDP
58 58
59 See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf> 59 See <http://www.dig64.org/specifications/DIG64_HCDPv20_042804.pdf>
60 60
61config DELL_RBU
62 tristate "BIOS update support for DELL systems via sysfs"
63 select FW_LOADER
64 help
65 Say m if you want to have the option of updating the BIOS for your
66 DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
67 supporting application to comunicate with the BIOS regarding the new
68 image for the image update to take effect.
69 See <file:Documentation/dell_rbu.txt> for more details on the driver.
70
71config DCDBAS
72 tristate "Dell Systems Management Base Driver"
73 depends on X86 || X86_64
74 default m
75 help
76 The Dell Systems Management Base Driver provides a sysfs interface
77 for systems management software to perform System Management
78 Interrupts (SMIs) and Host Control Actions (system power cycle or
79 power off after OS shutdown) on certain Dell systems.
80
81 See <file:Documentation/dcdbas.txt> for more details on the driver
82 and the Dell systems on which Dell systems management software makes
83 use of this driver.
84
85 Say Y or M here to enable the driver for use by Dell systems
86 management software such as Dell OpenManage.
87
61endmenu 88endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 90fd0b26db8b..85429979d0db 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -4,3 +4,5 @@
4obj-$(CONFIG_EDD) += edd.o 4obj-$(CONFIG_EDD) += edd.o
5obj-$(CONFIG_EFI_VARS) += efivars.o 5obj-$(CONFIG_EFI_VARS) += efivars.o
6obj-$(CONFIG_EFI_PCDP) += pcdp.o 6obj-$(CONFIG_EFI_PCDP) += pcdp.o
7obj-$(CONFIG_DELL_RBU) += dell_rbu.o
8obj-$(CONFIG_DCDBAS) += dcdbas.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
new file mode 100644
index 000000000000..955537fe9958
--- /dev/null
+++ b/drivers/firmware/dcdbas.c
@@ -0,0 +1,596 @@
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-2005 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/device.h>
24#include <linux/dma-mapping.h>
25#include <linux/errno.h>
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/mc146818rtc.h>
29#include <linux/module.h>
30#include <linux/reboot.h>
31#include <linux/sched.h>
32#include <linux/smp.h>
33#include <linux/spinlock.h>
34#include <linux/string.h>
35#include <linux/types.h>
36#include <asm/io.h>
37#include <asm/semaphore.h>
38
39#include "dcdbas.h"
40
41#define DRIVER_NAME "dcdbas"
42#define DRIVER_VERSION "5.6.0-1"
43#define DRIVER_DESCRIPTION "Dell Systems Management Base Driver"
44
45static struct platform_device *dcdbas_pdev;
46
47static u8 *smi_data_buf;
48static dma_addr_t smi_data_buf_handle;
49static unsigned long smi_data_buf_size;
50static u32 smi_data_buf_phys_addr;
51static DECLARE_MUTEX(smi_data_lock);
52
53static unsigned int host_control_action;
54static unsigned int host_control_smi_type;
55static unsigned int host_control_on_shutdown;
56
57/**
58 * smi_data_buf_free: free SMI data buffer
59 */
60static void smi_data_buf_free(void)
61{
62 if (!smi_data_buf)
63 return;
64
65 dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
66 __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
67
68 dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf,
69 smi_data_buf_handle);
70 smi_data_buf = NULL;
71 smi_data_buf_handle = 0;
72 smi_data_buf_phys_addr = 0;
73 smi_data_buf_size = 0;
74}
75
76/**
77 * smi_data_buf_realloc: grow SMI data buffer if needed
78 */
79static int smi_data_buf_realloc(unsigned long size)
80{
81 void *buf;
82 dma_addr_t handle;
83
84 if (smi_data_buf_size >= size)
85 return 0;
86
87 if (size > MAX_SMI_DATA_BUF_SIZE)
88 return -EINVAL;
89
90 /* new buffer is needed */
91 buf = dma_alloc_coherent(&dcdbas_pdev->dev, size, &handle, GFP_KERNEL);
92 if (!buf) {
93 dev_dbg(&dcdbas_pdev->dev,
94 "%s: failed to allocate memory size %lu\n",
95 __FUNCTION__, size);
96 return -ENOMEM;
97 }
98 /* memory zeroed by dma_alloc_coherent */
99
100 if (smi_data_buf)
101 memcpy(buf, smi_data_buf, smi_data_buf_size);
102
103 /* free any existing buffer */
104 smi_data_buf_free();
105
106 /* set up new buffer for use */
107 smi_data_buf = buf;
108 smi_data_buf_handle = handle;
109 smi_data_buf_phys_addr = (u32) virt_to_phys(buf);
110 smi_data_buf_size = size;
111
112 dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
113 __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
114
115 return 0;
116}
117
118static ssize_t smi_data_buf_phys_addr_show(struct device *dev,
119 struct device_attribute *attr,
120 char *buf)
121{
122 return sprintf(buf, "%x\n", smi_data_buf_phys_addr);
123}
124
125static ssize_t smi_data_buf_size_show(struct device *dev,
126 struct device_attribute *attr,
127 char *buf)
128{
129 return sprintf(buf, "%lu\n", smi_data_buf_size);
130}
131
132static ssize_t smi_data_buf_size_store(struct device *dev,
133 struct device_attribute *attr,
134 const char *buf, size_t count)
135{
136 unsigned long buf_size;
137 ssize_t ret;
138
139 buf_size = simple_strtoul(buf, NULL, 10);
140
141 /* make sure SMI data buffer is at least buf_size */
142 down(&smi_data_lock);
143 ret = smi_data_buf_realloc(buf_size);
144 up(&smi_data_lock);
145 if (ret)
146 return ret;
147
148 return count;
149}
150
151static ssize_t smi_data_read(struct kobject *kobj, char *buf, loff_t pos,
152 size_t count)
153{
154 size_t max_read;
155 ssize_t ret;
156
157 down(&smi_data_lock);
158
159 if (pos >= smi_data_buf_size) {
160 ret = 0;
161 goto out;
162 }
163
164 max_read = smi_data_buf_size - pos;
165 ret = min(max_read, count);
166 memcpy(buf, smi_data_buf + pos, ret);
167out:
168 up(&smi_data_lock);
169 return ret;
170}
171
172static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
173 size_t count)
174{
175 ssize_t ret;
176
177 down(&smi_data_lock);
178
179 ret = smi_data_buf_realloc(pos + count);
180 if (ret)
181 goto out;
182
183 memcpy(smi_data_buf + pos, buf, count);
184 ret = count;
185out:
186 up(&smi_data_lock);
187 return ret;
188}
189
190static ssize_t host_control_action_show(struct device *dev,
191 struct device_attribute *attr,
192 char *buf)
193{
194 return sprintf(buf, "%u\n", host_control_action);
195}
196
197static ssize_t host_control_action_store(struct device *dev,
198 struct device_attribute *attr,
199 const char *buf, size_t count)
200{
201 ssize_t ret;
202
203 /* make sure buffer is available for host control command */
204 down(&smi_data_lock);
205 ret = smi_data_buf_realloc(sizeof(struct apm_cmd));
206 up(&smi_data_lock);
207 if (ret)
208 return ret;
209
210 host_control_action = simple_strtoul(buf, NULL, 10);
211 return count;
212}
213
214static ssize_t host_control_smi_type_show(struct device *dev,
215 struct device_attribute *attr,
216 char *buf)
217{
218 return sprintf(buf, "%u\n", host_control_smi_type);
219}
220
221static ssize_t host_control_smi_type_store(struct device *dev,
222 struct device_attribute *attr,
223 const char *buf, size_t count)
224{
225 host_control_smi_type = simple_strtoul(buf, NULL, 10);
226 return count;
227}
228
229static ssize_t host_control_on_shutdown_show(struct device *dev,
230 struct device_attribute *attr,
231 char *buf)
232{
233 return sprintf(buf, "%u\n", host_control_on_shutdown);
234}
235
236static ssize_t host_control_on_shutdown_store(struct device *dev,
237 struct device_attribute *attr,
238 const char *buf, size_t count)
239{
240 host_control_on_shutdown = simple_strtoul(buf, NULL, 10);
241 return count;
242}
243
244/**
245 * smi_request: generate SMI request
246 *
247 * Called with smi_data_lock.
248 */
249static int smi_request(struct smi_cmd *smi_cmd)
250{
251 cpumask_t old_mask;
252 int ret = 0;
253
254 if (smi_cmd->magic != SMI_CMD_MAGIC) {
255 dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
256 __FUNCTION__);
257 return -EBADR;
258 }
259
260 /* SMI requires CPU 0 */
261 old_mask = current->cpus_allowed;
262 set_cpus_allowed(current, cpumask_of_cpu(0));
263 if (smp_processor_id() != 0) {
264 dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
265 __FUNCTION__);
266 ret = -EBUSY;
267 goto out;
268 }
269
270 /* generate SMI */
271 asm volatile (
272 "outb %b0,%w1"
273 : /* no output args */
274 : "a" (smi_cmd->command_code),
275 "d" (smi_cmd->command_address),
276 "b" (smi_cmd->ebx),
277 "c" (smi_cmd->ecx)
278 : "memory"
279 );
280
281out:
282 set_cpus_allowed(current, old_mask);
283 return ret;
284}
285
286/**
287 * smi_request_store:
288 *
289 * The valid values are:
290 * 0: zero SMI data buffer
291 * 1: generate calling interface SMI
292 * 2: generate raw SMI
293 *
294 * User application writes smi_cmd to smi_data before telling driver
295 * to generate SMI.
296 */
297static ssize_t smi_request_store(struct device *dev,
298 struct device_attribute *attr,
299 const char *buf, size_t count)
300{
301 struct smi_cmd *smi_cmd;
302 unsigned long val = simple_strtoul(buf, NULL, 10);
303 ssize_t ret;
304
305 down(&smi_data_lock);
306
307 if (smi_data_buf_size < sizeof(struct smi_cmd)) {
308 ret = -ENODEV;
309 goto out;
310 }
311 smi_cmd = (struct smi_cmd *)smi_data_buf;
312
313 switch (val) {
314 case 2:
315 /* Raw SMI */
316 ret = smi_request(smi_cmd);
317 if (!ret)
318 ret = count;
319 break;
320 case 1:
321 /* Calling Interface SMI */
322 smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer);
323 ret = smi_request(smi_cmd);
324 if (!ret)
325 ret = count;
326 break;
327 case 0:
328 memset(smi_data_buf, 0, smi_data_buf_size);
329 ret = count;
330 break;
331 default:
332 ret = -EINVAL;
333 break;
334 }
335
336out:
337 up(&smi_data_lock);
338 return ret;
339}
340
341/**
342 * host_control_smi: generate host control SMI
343 *
344 * Caller must set up the host control command in smi_data_buf.
345 */
346static int host_control_smi(void)
347{
348 struct apm_cmd *apm_cmd;
349 u8 *data;
350 unsigned long flags;
351 u32 num_ticks;
352 s8 cmd_status;
353 u8 index;
354
355 apm_cmd = (struct apm_cmd *)smi_data_buf;
356 apm_cmd->status = ESM_STATUS_CMD_UNSUCCESSFUL;
357
358 switch (host_control_smi_type) {
359 case HC_SMITYPE_TYPE1:
360 spin_lock_irqsave(&rtc_lock, flags);
361 /* write SMI data buffer physical address */
362 data = (u8 *)&smi_data_buf_phys_addr;
363 for (index = PE1300_CMOS_CMD_STRUCT_PTR;
364 index < (PE1300_CMOS_CMD_STRUCT_PTR + 4);
365 index++, data++) {
366 outb(index,
367 (CMOS_BASE_PORT + CMOS_PAGE2_INDEX_PORT_PIIX4));
368 outb(*data,
369 (CMOS_BASE_PORT + CMOS_PAGE2_DATA_PORT_PIIX4));
370 }
371
372 /* first set status to -1 as called by spec */
373 cmd_status = ESM_STATUS_CMD_UNSUCCESSFUL;
374 outb((u8) cmd_status, PCAT_APM_STATUS_PORT);
375
376 /* generate SMM call */
377 outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
378 spin_unlock_irqrestore(&rtc_lock, flags);
379
380 /* wait a few to see if it executed */
381 num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
382 while ((cmd_status = inb(PCAT_APM_STATUS_PORT))
383 == ESM_STATUS_CMD_UNSUCCESSFUL) {
384 num_ticks--;
385 if (num_ticks == EXPIRED_TIMER)
386 return -ETIME;
387 }
388 break;
389
390 case HC_SMITYPE_TYPE2:
391 case HC_SMITYPE_TYPE3:
392 spin_lock_irqsave(&rtc_lock, flags);
393 /* write SMI data buffer physical address */
394 data = (u8 *)&smi_data_buf_phys_addr;
395 for (index = PE1400_CMOS_CMD_STRUCT_PTR;
396 index < (PE1400_CMOS_CMD_STRUCT_PTR + 4);
397 index++, data++) {
398 outb(index, (CMOS_BASE_PORT + CMOS_PAGE1_INDEX_PORT));
399 outb(*data, (CMOS_BASE_PORT + CMOS_PAGE1_DATA_PORT));
400 }
401
402 /* generate SMM call */
403 if (host_control_smi_type == HC_SMITYPE_TYPE3)
404 outb(ESM_APM_CMD, PCAT_APM_CONTROL_PORT);
405 else
406 outb(ESM_APM_CMD, PE1400_APM_CONTROL_PORT);
407
408 /* restore RTC index pointer since it was written to above */
409 CMOS_READ(RTC_REG_C);
410 spin_unlock_irqrestore(&rtc_lock, flags);
411
412 /* read control port back to serialize write */
413 cmd_status = inb(PE1400_APM_CONTROL_PORT);
414
415 /* wait a few to see if it executed */
416 num_ticks = TIMEOUT_USEC_SHORT_SEMA_BLOCKING;
417 while (apm_cmd->status == ESM_STATUS_CMD_UNSUCCESSFUL) {
418 num_ticks--;
419 if (num_ticks == EXPIRED_TIMER)
420 return -ETIME;
421 }
422 break;
423
424 default:
425 dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n",
426 __FUNCTION__, host_control_smi_type);
427 return -ENOSYS;
428 }
429
430 return 0;
431}
432
433/**
434 * dcdbas_host_control: initiate host control
435 *
436 * This function is called by the driver after the system has
437 * finished shutting down if the user application specified a
438 * host control action to perform on shutdown. It is safe to
439 * use smi_data_buf at this point because the system has finished
440 * shutting down and no userspace apps are running.
441 */
442static void dcdbas_host_control(void)
443{
444 struct apm_cmd *apm_cmd;
445 u8 action;
446
447 if (host_control_action == HC_ACTION_NONE)
448 return;
449
450 action = host_control_action;
451 host_control_action = HC_ACTION_NONE;
452
453 if (!smi_data_buf) {
454 dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__);
455 return;
456 }
457
458 if (smi_data_buf_size < sizeof(struct apm_cmd)) {
459 dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
460 __FUNCTION__);
461 return;
462 }
463
464 apm_cmd = (struct apm_cmd *)smi_data_buf;
465
466 /* power off takes precedence */
467 if (action & HC_ACTION_HOST_CONTROL_POWEROFF) {
468 apm_cmd->command = ESM_APM_POWER_CYCLE;
469 apm_cmd->reserved = 0;
470 *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 0;
471 host_control_smi();
472 } else if (action & HC_ACTION_HOST_CONTROL_POWERCYCLE) {
473 apm_cmd->command = ESM_APM_POWER_CYCLE;
474 apm_cmd->reserved = 0;
475 *((s16 *)&apm_cmd->parameters.shortreq.parm[0]) = (s16) 20;
476 host_control_smi();
477 }
478}
479
480/**
481 * dcdbas_reboot_notify: handle reboot notification for host control
482 */
483static int dcdbas_reboot_notify(struct notifier_block *nb, unsigned long code,
484 void *unused)
485{
486 static unsigned int notify_cnt = 0;
487
488 switch (code) {
489 case SYS_DOWN:
490 case SYS_HALT:
491 case SYS_POWER_OFF:
492 if (host_control_on_shutdown) {
493 /* firmware is going to perform host control action */
494 if (++notify_cnt == 2) {
495 printk(KERN_WARNING
496 "Please wait for shutdown "
497 "action to complete...\n");
498 dcdbas_host_control();
499 }
500 /*
501 * register again and initiate the host control
502 * action on the second notification to allow
503 * everyone that registered to be notified
504 */
505 register_reboot_notifier(nb);
506 }
507 break;
508 }
509
510 return NOTIFY_DONE;
511}
512
513static struct notifier_block dcdbas_reboot_nb = {
514 .notifier_call = dcdbas_reboot_notify,
515 .next = NULL,
516 .priority = 0
517};
518
519static DCDBAS_BIN_ATTR_RW(smi_data);
520
521static struct bin_attribute *dcdbas_bin_attrs[] = {
522 &bin_attr_smi_data,
523 NULL
524};
525
526static DCDBAS_DEV_ATTR_RW(smi_data_buf_size);
527static DCDBAS_DEV_ATTR_RO(smi_data_buf_phys_addr);
528static DCDBAS_DEV_ATTR_WO(smi_request);
529static DCDBAS_DEV_ATTR_RW(host_control_action);
530static DCDBAS_DEV_ATTR_RW(host_control_smi_type);
531static DCDBAS_DEV_ATTR_RW(host_control_on_shutdown);
532
533static struct device_attribute *dcdbas_dev_attrs[] = {
534 &dev_attr_smi_data_buf_size,
535 &dev_attr_smi_data_buf_phys_addr,
536 &dev_attr_smi_request,
537 &dev_attr_host_control_action,
538 &dev_attr_host_control_smi_type,
539 &dev_attr_host_control_on_shutdown,
540 NULL
541};
542
543/**
544 * dcdbas_init: initialize driver
545 */
546static int __init dcdbas_init(void)
547{
548 int i;
549
550 host_control_action = HC_ACTION_NONE;
551 host_control_smi_type = HC_SMITYPE_NONE;
552
553 dcdbas_pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
554 if (IS_ERR(dcdbas_pdev))
555 return PTR_ERR(dcdbas_pdev);
556
557 /*
558 * BIOS SMI calls require buffer addresses be in 32-bit address space.
559 * This is done by setting the DMA mask below.
560 */
561 dcdbas_pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
562 dcdbas_pdev->dev.dma_mask = &dcdbas_pdev->dev.coherent_dma_mask;
563
564 register_reboot_notifier(&dcdbas_reboot_nb);
565
566 for (i = 0; dcdbas_bin_attrs[i]; i++)
567 sysfs_create_bin_file(&dcdbas_pdev->dev.kobj,
568 dcdbas_bin_attrs[i]);
569
570 for (i = 0; dcdbas_dev_attrs[i]; i++)
571 device_create_file(&dcdbas_pdev->dev, dcdbas_dev_attrs[i]);
572
573 dev_info(&dcdbas_pdev->dev, "%s (version %s)\n",
574 DRIVER_DESCRIPTION, DRIVER_VERSION);
575
576 return 0;
577}
578
579/**
580 * dcdbas_exit: perform driver cleanup
581 */
582static void __exit dcdbas_exit(void)
583{
584 platform_device_unregister(dcdbas_pdev);
585 unregister_reboot_notifier(&dcdbas_reboot_nb);
586 smi_data_buf_free();
587}
588
589module_init(dcdbas_init);
590module_exit(dcdbas_exit);
591
592MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
593MODULE_VERSION(DRIVER_VERSION);
594MODULE_AUTHOR("Dell Inc.");
595MODULE_LICENSE("GPL");
596
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
new file mode 100644
index 000000000000..58a85182b3e8
--- /dev/null
+++ b/drivers/firmware/dcdbas.h
@@ -0,0 +1,107 @@
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/input.h>
21#include <linux/sysfs.h>
22#include <linux/types.h>
23
24#define MAX_SMI_DATA_BUF_SIZE (256 * 1024)
25
26#define HC_ACTION_NONE (0)
27#define HC_ACTION_HOST_CONTROL_POWEROFF BIT(1)
28#define HC_ACTION_HOST_CONTROL_POWERCYCLE BIT(2)
29
30#define HC_SMITYPE_NONE (0)
31#define HC_SMITYPE_TYPE1 (1)
32#define HC_SMITYPE_TYPE2 (2)
33#define HC_SMITYPE_TYPE3 (3)
34
35#define ESM_APM_CMD (0x0A0)
36#define ESM_APM_POWER_CYCLE (0x10)
37#define ESM_STATUS_CMD_UNSUCCESSFUL (-1)
38
39#define CMOS_BASE_PORT (0x070)
40#define CMOS_PAGE1_INDEX_PORT (0)
41#define CMOS_PAGE1_DATA_PORT (1)
42#define CMOS_PAGE2_INDEX_PORT_PIIX4 (2)
43#define CMOS_PAGE2_DATA_PORT_PIIX4 (3)
44#define PE1400_APM_CONTROL_PORT (0x0B0)
45#define PCAT_APM_CONTROL_PORT (0x0B2)
46#define PCAT_APM_STATUS_PORT (0x0B3)
47#define PE1300_CMOS_CMD_STRUCT_PTR (0x38)
48#define PE1400_CMOS_CMD_STRUCT_PTR (0x70)
49
50#define MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN (14)
51#define MAX_SYSMGMT_LONGCMD_SGENTRY_NUM (16)
52
53#define TIMEOUT_USEC_SHORT_SEMA_BLOCKING (10000)
54#define EXPIRED_TIMER (0)
55
56#define SMI_CMD_MAGIC (0x534D4931)
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 .owner = THIS_MODULE }, \
72 .read = _name##_read, \
73 .write = _name##_write, \
74}
75
76struct smi_cmd {
77 __u32 magic;
78 __u32 ebx;
79 __u32 ecx;
80 __u16 command_address;
81 __u8 command_code;
82 __u8 reserved;
83 __u8 command_buffer[1];
84} __attribute__ ((packed));
85
86struct apm_cmd {
87 __u8 command;
88 __s8 status;
89 __u16 reserved;
90 union {
91 struct {
92 __u8 parm[MAX_SYSMGMT_SHORTCMD_PARMBUF_LEN];
93 } __attribute__ ((packed)) shortreq;
94
95 struct {
96 __u16 num_sg_entries;
97 struct {
98 __u32 size;
99 __u64 addr;
100 } __attribute__ ((packed))
101 sglist[MAX_SYSMGMT_LONGCMD_SGENTRY_NUM];
102 } __attribute__ ((packed)) longreq;
103 } __attribute__ ((packed)) parameters;
104} __attribute__ ((packed));
105
106#endif /* _DCDBAS_H_ */
107
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
new file mode 100644
index 000000000000..3b865f34a095
--- /dev/null
+++ b/drivers/firmware/dell_rbu.c
@@ -0,0 +1,634 @@
1/*
2 * dell_rbu.c
3 * Bios Update driver for Dell systems
4 * Author: Dell Inc
5 * Abhay Salunke <abhay_salunke@dell.com>
6 *
7 * Copyright (C) 2005 Dell Inc.
8 *
9 * Remote BIOS Update (rbu) driver is used for updating DELL BIOS by
10 * creating entries in the /sys file systems on Linux 2.6 and higher
11 * kernels. The driver supports two mechanism to update the BIOS namely
12 * contiguous and packetized. Both these methods still require having some
13 * application to set the CMOS bit indicating the BIOS to update itself
14 * after a reboot.
15 *
16 * Contiguous method:
17 * This driver writes the incoming data in a monolithic image by allocating
18 * contiguous physical pages large enough to accommodate the incoming BIOS
19 * image size.
20 *
21 * Packetized method:
22 * The driver writes the incoming packet image by allocating a new packet
23 * on every time the packet data is written. This driver requires an
24 * application to break the BIOS image in to fixed sized packet chunks.
25 *
26 * See Documentation/dell_rbu.txt for more info.
27 *
28 * This program is free software; you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License v2.0 as published by
30 * the Free Software Foundation
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 */
37#include <linux/version.h>
38#include <linux/config.h>
39#include <linux/init.h>
40#include <linux/module.h>
41#include <linux/string.h>
42#include <linux/errno.h>
43#include <linux/blkdev.h>
44#include <linux/device.h>
45#include <linux/spinlock.h>
46#include <linux/moduleparam.h>
47#include <linux/firmware.h>
48#include <linux/dma-mapping.h>
49
50MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
51MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
52MODULE_LICENSE("GPL");
53MODULE_VERSION("1.0");
54
55#define BIOS_SCAN_LIMIT 0xffffffff
56#define MAX_IMAGE_LENGTH 16
57static struct _rbu_data {
58 void *image_update_buffer;
59 unsigned long image_update_buffer_size;
60 unsigned long bios_image_size;
61 int image_update_ordernum;
62 int dma_alloc;
63 spinlock_t lock;
64 unsigned long packet_read_count;
65 unsigned long packet_write_count;
66 unsigned long num_packets;
67 unsigned long packetsize;
68} rbu_data;
69
70static char image_type[MAX_IMAGE_LENGTH] = "mono";
71module_param_string(image_type, image_type, sizeof(image_type), 0);
72MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet");
73
74struct packet_data {
75 struct list_head list;
76 size_t length;
77 void *data;
78 int ordernum;
79};
80
81static struct packet_data packet_data_head;
82
83static struct platform_device *rbu_device;
84static int context;
85static dma_addr_t dell_rbu_dmaaddr;
86
87static void init_packet_head(void)
88{
89 INIT_LIST_HEAD(&packet_data_head.list);
90 rbu_data.packet_write_count = 0;
91 rbu_data.packet_read_count = 0;
92 rbu_data.num_packets = 0;
93 rbu_data.packetsize = 0;
94}
95
96static int fill_last_packet(void *data, size_t length)
97{
98 struct list_head *ptemp_list;
99 struct packet_data *packet = NULL;
100 int packet_count = 0;
101
102 pr_debug("fill_last_packet: entry \n");
103
104 if (!rbu_data.num_packets) {
105 pr_debug("fill_last_packet: num_packets=0\n");
106 return -ENOMEM;
107 }
108
109 packet_count = rbu_data.num_packets;
110
111 ptemp_list = (&packet_data_head.list)->prev;
112
113 packet = list_entry(ptemp_list, struct packet_data, list);
114
115 if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) {
116 pr_debug("dell_rbu:%s: packet size data "
117 "overrun\n", __FUNCTION__);
118 return -EINVAL;
119 }
120
121 pr_debug("fill_last_packet : buffer = %p\n", packet->data);
122
123 memcpy((packet->data + rbu_data.packet_write_count), data, length);
124
125 if ((rbu_data.packet_write_count + length) == rbu_data.packetsize) {
126 /*
127 * this was the last data chunk in the packet
128 * so reinitialize the packet data counter to zero
129 */
130 rbu_data.packet_write_count = 0;
131 } else
132 rbu_data.packet_write_count += length;
133
134 pr_debug("fill_last_packet: exit \n");
135 return 0;
136}
137
138static int create_packet(size_t length)
139{
140 struct packet_data *newpacket;
141 int ordernum = 0;
142
143 pr_debug("create_packet: entry \n");
144
145 if (!rbu_data.packetsize) {
146 pr_debug("create_packet: packetsize not specified\n");
147 return -EINVAL;
148 }
149
150 newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL);
151 if (!newpacket) {
152 printk(KERN_WARNING
153 "dell_rbu:%s: failed to allocate new "
154 "packet\n", __FUNCTION__);
155 return -ENOMEM;
156 }
157
158 ordernum = get_order(length);
159 /*
160 * there is no upper limit on memory
161 * address for packetized mechanism
162 */
163 newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL,
164 ordernum);
165
166 pr_debug("create_packet: newpacket %p\n", newpacket->data);
167
168 if (!newpacket->data) {
169 printk(KERN_WARNING
170 "dell_rbu:%s: failed to allocate new "
171 "packet\n", __FUNCTION__);
172 kfree(newpacket);
173 return -ENOMEM;
174 }
175
176 newpacket->ordernum = ordernum;
177 ++rbu_data.num_packets;
178 /*
179 * initialize the newly created packet headers
180 */
181 INIT_LIST_HEAD(&newpacket->list);
182 list_add_tail(&newpacket->list, &packet_data_head.list);
183 /*
184 * packets have fixed size
185 */
186 newpacket->length = rbu_data.packetsize;
187
188 pr_debug("create_packet: exit \n");
189
190 return 0;
191}
192
193static int packetize_data(void *data, size_t length)
194{
195 int rc = 0;
196
197 if (!rbu_data.packet_write_count) {
198 if ((rc = create_packet(length)))
199 return rc;
200 }
201 if ((rc = fill_last_packet(data, length)))
202 return rc;
203
204 return rc;
205}
206
207static int
208do_packet_read(char *data, struct list_head *ptemp_list,
209 int length, int bytes_read, int *list_read_count)
210{
211 void *ptemp_buf;
212 struct packet_data *newpacket = NULL;
213 int bytes_copied = 0;
214 int j = 0;
215
216 newpacket = list_entry(ptemp_list, struct packet_data, list);
217 *list_read_count += newpacket->length;
218
219 if (*list_read_count > bytes_read) {
220 /* point to the start of unread data */
221 j = newpacket->length - (*list_read_count - bytes_read);
222 /* point to the offset in the packet buffer */
223 ptemp_buf = (u8 *) newpacket->data + j;
224 /*
225 * check if there is enough room in
226 * * the incoming buffer
227 */
228 if (length > (*list_read_count - bytes_read))
229 /*
230 * copy what ever is there in this
231 * packet and move on
232 */
233 bytes_copied = (*list_read_count - bytes_read);
234 else
235 /* copy the remaining */
236 bytes_copied = length;
237 memcpy(data, ptemp_buf, bytes_copied);
238 }
239 return bytes_copied;
240}
241
242static int packet_read_list(char *data, size_t * pread_length)
243{
244 struct list_head *ptemp_list;
245 int temp_count = 0;
246 int bytes_copied = 0;
247 int bytes_read = 0;
248 int remaining_bytes = 0;
249 char *pdest = data;
250
251 /* check if we have any packets */
252 if (0 == rbu_data.num_packets)
253 return -ENOMEM;
254
255 remaining_bytes = *pread_length;
256 bytes_read = rbu_data.packet_read_count;
257
258 ptemp_list = (&packet_data_head.list)->next;
259 while (!list_empty(ptemp_list)) {
260 bytes_copied = do_packet_read(pdest, ptemp_list,
261 remaining_bytes, bytes_read,
262 &temp_count);
263 remaining_bytes -= bytes_copied;
264 bytes_read += bytes_copied;
265 pdest += bytes_copied;
266 /*
267 * check if we reached end of buffer before reaching the
268 * last packet
269 */
270 if (remaining_bytes == 0)
271 break;
272
273 ptemp_list = ptemp_list->next;
274 }
275 /*finally set the bytes read */
276 *pread_length = bytes_read - rbu_data.packet_read_count;
277 rbu_data.packet_read_count = bytes_read;
278 return 0;
279}
280
281static void packet_empty_list(void)
282{
283 struct list_head *ptemp_list;
284 struct list_head *pnext_list;
285 struct packet_data *newpacket;
286
287 ptemp_list = (&packet_data_head.list)->next;
288 while (!list_empty(ptemp_list)) {
289 newpacket =
290 list_entry(ptemp_list, struct packet_data, list);
291 pnext_list = ptemp_list->next;
292 list_del(ptemp_list);
293 ptemp_list = pnext_list;
294 /*
295 * zero out the RBU packet memory before freeing
296 * to make sure there are no stale RBU packets left in memory
297 */
298 memset(newpacket->data, 0, rbu_data.packetsize);
299 free_pages((unsigned long)newpacket->data,
300 newpacket->ordernum);
301 kfree(newpacket);
302 }
303 rbu_data.packet_write_count = 0;
304 rbu_data.packet_read_count = 0;
305 rbu_data.num_packets = 0;
306 rbu_data.packetsize = 0;
307}
308
309/*
310 * img_update_free: Frees the buffer allocated for storing BIOS image
311 * Always called with lock held and returned with lock held
312 */
313static void img_update_free(void)
314{
315 if (!rbu_data.image_update_buffer)
316 return;
317 /*
318 * zero out this buffer before freeing it to get rid of any stale
319 * BIOS image copied in memory.
320 */
321 memset(rbu_data.image_update_buffer, 0,
322 rbu_data.image_update_buffer_size);
323 if (rbu_data.dma_alloc == 1)
324 dma_free_coherent(NULL, rbu_data.bios_image_size,
325 rbu_data.image_update_buffer,
326 dell_rbu_dmaaddr);
327 else
328 free_pages((unsigned long)rbu_data.image_update_buffer,
329 rbu_data.image_update_ordernum);
330
331 /*
332 * Re-initialize the rbu_data variables after a free
333 */
334 rbu_data.image_update_ordernum = -1;
335 rbu_data.image_update_buffer = NULL;
336 rbu_data.image_update_buffer_size = 0;
337 rbu_data.bios_image_size = 0;
338 rbu_data.dma_alloc = 0;
339}
340
341/*
342 * img_update_realloc: This function allocates the contiguous pages to
343 * accommodate the requested size of data. The memory address and size
344 * values are stored globally and on every call to this function the new
345 * size is checked to see if more data is required than the existing size.
346 * If true the previous memory is freed and new allocation is done to
347 * accommodate the new size. If the incoming size is less then than the
348 * already allocated size, then that memory is reused. This function is
349 * called with lock held and returns with lock held.
350 */
351static int img_update_realloc(unsigned long size)
352{
353 unsigned char *image_update_buffer = NULL;
354 unsigned long rc;
355 unsigned long img_buf_phys_addr;
356 int ordernum;
357 int dma_alloc = 0;
358
359 /*
360 * check if the buffer of sufficient size has been
361 * already allocated
362 */
363 if (rbu_data.image_update_buffer_size >= size) {
364 /*
365 * check for corruption
366 */
367 if ((size != 0) && (rbu_data.image_update_buffer == NULL)) {
368 printk(KERN_ERR "dell_rbu:%s: corruption "
369 "check failed\n", __FUNCTION__);
370 return -EINVAL;
371 }
372 /*
373 * we have a valid pre-allocated buffer with
374 * sufficient size
375 */
376 return 0;
377 }
378
379 /*
380 * free any previously allocated buffer
381 */
382 img_update_free();
383
384 spin_unlock(&rbu_data.lock);
385
386 ordernum = get_order(size);
387 image_update_buffer =
388 (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum);
389
390 img_buf_phys_addr =
391 (unsigned long)virt_to_phys(image_update_buffer);
392
393 if (img_buf_phys_addr > BIOS_SCAN_LIMIT) {
394 free_pages((unsigned long)image_update_buffer, ordernum);
395 ordernum = -1;
396 image_update_buffer = dma_alloc_coherent(NULL, size,
397 &dell_rbu_dmaaddr,
398 GFP_KERNEL);
399 dma_alloc = 1;
400 }
401
402 spin_lock(&rbu_data.lock);
403
404 if (image_update_buffer != NULL) {
405 rbu_data.image_update_buffer = image_update_buffer;
406 rbu_data.image_update_buffer_size = size;
407 rbu_data.bios_image_size =
408 rbu_data.image_update_buffer_size;
409 rbu_data.image_update_ordernum = ordernum;
410 rbu_data.dma_alloc = dma_alloc;
411 rc = 0;
412 } else {
413 pr_debug("Not enough memory for image update:"
414 "size = %ld\n", size);
415 rc = -ENOMEM;
416 }
417
418 return rc;
419}
420
421static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count)
422{
423 int retval;
424 size_t bytes_left;
425 size_t data_length;
426 char *ptempBuf = buffer;
427 unsigned long imagesize;
428
429 /* check to see if we have something to return */
430 if (rbu_data.num_packets == 0) {
431 pr_debug("read_packet_data: no packets written\n");
432 retval = -ENOMEM;
433 goto read_rbu_data_exit;
434 }
435
436 imagesize = rbu_data.num_packets * rbu_data.packetsize;
437
438 if (pos > imagesize) {
439 retval = 0;
440 printk(KERN_WARNING "dell_rbu:read_packet_data: "
441 "data underrun\n");
442 goto read_rbu_data_exit;
443 }
444
445 bytes_left = imagesize - pos;
446 data_length = min(bytes_left, count);
447
448 if ((retval = packet_read_list(ptempBuf, &data_length)) < 0)
449 goto read_rbu_data_exit;
450
451 if ((pos + count) > imagesize) {
452 rbu_data.packet_read_count = 0;
453 /* this was the last copy */
454 retval = bytes_left;
455 } else
456 retval = count;
457
458 read_rbu_data_exit:
459 return retval;
460}
461
462static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
463{
464 unsigned char *ptemp = NULL;
465 size_t bytes_left = 0;
466 size_t data_length = 0;
467 ssize_t ret_count = 0;
468
469 /* check to see if we have something to return */
470 if ((rbu_data.image_update_buffer == NULL) ||
471 (rbu_data.bios_image_size == 0)) {
472 pr_debug("read_rbu_data_mono: image_update_buffer %p ,"
473 "bios_image_size %lu\n",
474 rbu_data.image_update_buffer,
475 rbu_data.bios_image_size);
476 ret_count = -ENOMEM;
477 goto read_rbu_data_exit;
478 }
479
480 if (pos > rbu_data.bios_image_size) {
481 ret_count = 0;
482 goto read_rbu_data_exit;
483 }
484
485 bytes_left = rbu_data.bios_image_size - pos;
486 data_length = min(bytes_left, count);
487
488 ptemp = rbu_data.image_update_buffer;
489 memcpy(buffer, (ptemp + pos), data_length);
490
491 if ((pos + count) > rbu_data.bios_image_size)
492 /* this was the last copy */
493 ret_count = bytes_left;
494 else
495 ret_count = count;
496 read_rbu_data_exit:
497 return ret_count;
498}
499
500static ssize_t
501read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count)
502{
503 ssize_t ret_count = 0;
504
505 spin_lock(&rbu_data.lock);
506
507 if (!strcmp(image_type, "mono"))
508 ret_count = read_rbu_mono_data(buffer, pos, count);
509 else if (!strcmp(image_type, "packet"))
510 ret_count = read_packet_data(buffer, pos, count);
511 else
512 pr_debug("read_rbu_data: invalid image type specified\n");
513
514 spin_unlock(&rbu_data.lock);
515 return ret_count;
516}
517
518static ssize_t
519read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
520 size_t count)
521{
522 int size = 0;
523 if (!pos)
524 size = sprintf(buffer, "%s\n", image_type);
525 return size;
526}
527
528static ssize_t
529write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos,
530 size_t count)
531{
532 int rc = count;
533 spin_lock(&rbu_data.lock);
534
535 if (strlen(buffer) < MAX_IMAGE_LENGTH)
536 sscanf(buffer, "%s", image_type);
537 else
538 printk(KERN_WARNING "dell_rbu: image_type is invalid"
539 "max chars = %d, \n incoming str--%s-- \n",
540 MAX_IMAGE_LENGTH, buffer);
541
542 /* we must free all previous allocations */
543 packet_empty_list();
544 img_update_free();
545
546 spin_unlock(&rbu_data.lock);
547 return rc;
548
549}
550
551static struct bin_attribute rbu_data_attr = {
552 .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444},
553 .read = read_rbu_data,
554};
555
556static struct bin_attribute rbu_image_type_attr = {
557 .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644},
558 .read = read_rbu_image_type,
559 .write = write_rbu_image_type,
560};
561
562static void callbackfn_rbu(const struct firmware *fw, void *context)
563{
564 int rc = 0;
565
566 if (!fw || !fw->size)
567 return;
568
569 spin_lock(&rbu_data.lock);
570 if (!strcmp(image_type, "mono")) {
571 if (!img_update_realloc(fw->size))
572 memcpy(rbu_data.image_update_buffer,
573 fw->data, fw->size);
574 } else if (!strcmp(image_type, "packet")) {
575 if (!rbu_data.packetsize)
576 rbu_data.packetsize = fw->size;
577 else if (rbu_data.packetsize != fw->size) {
578 packet_empty_list();
579 rbu_data.packetsize = fw->size;
580 }
581 packetize_data(fw->data, fw->size);
582 } else
583 pr_debug("invalid image type specified.\n");
584 spin_unlock(&rbu_data.lock);
585
586 rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
587 "dell_rbu", &rbu_device->dev,
588 &context, callbackfn_rbu);
589 if (rc)
590 printk(KERN_ERR
591 "dell_rbu:%s request_firmware_nowait failed"
592 " %d\n", __FUNCTION__, rc);
593}
594
595static int __init dcdrbu_init(void)
596{
597 int rc = 0;
598 spin_lock_init(&rbu_data.lock);
599
600 init_packet_head();
601 rbu_device =
602 platform_device_register_simple("dell_rbu", -1, NULL, 0);
603 if (!rbu_device) {
604 printk(KERN_ERR
605 "dell_rbu:%s:platform_device_register_simple "
606 "failed\n", __FUNCTION__);
607 return -EIO;
608 }
609
610 sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
611 sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
612
613 rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
614 "dell_rbu", &rbu_device->dev,
615 &context, callbackfn_rbu);
616 if (rc)
617 printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait"
618 " failed %d\n", __FUNCTION__, rc);
619
620 return rc;
621
622}
623
624static __exit void dcdrbu_exit(void)
625{
626 spin_lock(&rbu_data.lock);
627 packet_empty_list();
628 img_update_free();
629 spin_unlock(&rbu_data.lock);
630 platform_device_unregister(rbu_device);
631}
632
633module_exit(dcdrbu_exit);
634module_init(dcdrbu_init);