aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/kernel/mca.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ia64/sn/kernel/mca.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/ia64/sn/kernel/mca.c')
-rw-r--r--arch/ia64/sn/kernel/mca.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c
new file mode 100644
index 000000000000..857774bb2c9a
--- /dev/null
+++ b/arch/ia64/sn/kernel/mca.c
@@ -0,0 +1,135 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
7 */
8
9#include <linux/types.h>
10#include <linux/kernel.h>
11#include <linux/timer.h>
12#include <linux/vmalloc.h>
13#include <asm/mca.h>
14#include <asm/sal.h>
15#include <asm/sn/sn_sal.h>
16
17/*
18 * Interval for calling SAL to poll for errors that do NOT cause error
19 * interrupts. SAL will raise a CPEI if any errors are present that
20 * need to be logged.
21 */
22#define CPEI_INTERVAL (5*HZ)
23
24struct timer_list sn_cpei_timer;
25void sn_init_cpei_timer(void);
26
27/* Printing oemdata from mca uses data that is not passed through SAL, it is
28 * global. Only one user at a time.
29 */
30static DECLARE_MUTEX(sn_oemdata_mutex);
31static u8 **sn_oemdata;
32static u64 *sn_oemdata_size, sn_oemdata_bufsize;
33
34/*
35 * print_hook
36 *
37 * This function is the callback routine that SAL calls to log error
38 * info for platform errors. buf is appended to sn_oemdata, resizing as
39 * required.
40 */
41static int print_hook(const char *fmt, ...)
42{
43 char buf[400];
44 int len;
45 va_list args;
46 va_start(args, fmt);
47 vsnprintf(buf, sizeof(buf), fmt, args);
48 va_end(args);
49 len = strlen(buf);
50 while (*sn_oemdata_size + len + 1 > sn_oemdata_bufsize) {
51 u8 *newbuf = vmalloc(sn_oemdata_bufsize += 1000);
52 if (!newbuf) {
53 printk(KERN_ERR "%s: unable to extend sn_oemdata\n",
54 __FUNCTION__);
55 return 0;
56 }
57 memcpy(newbuf, *sn_oemdata, *sn_oemdata_size);
58 vfree(*sn_oemdata);
59 *sn_oemdata = newbuf;
60 }
61 memcpy(*sn_oemdata + *sn_oemdata_size, buf, len + 1);
62 *sn_oemdata_size += len;
63 return 0;
64}
65
66static void sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
67{
68 /*
69 * this function's sole purpose is to call SAL when we receive
70 * a CE interrupt from SHUB or when the timer routine decides
71 * we need to call SAL to check for CEs.
72 */
73
74 /* CALL SAL_LOG_CE */
75
76 ia64_sn_plat_cpei_handler();
77}
78
79static void sn_cpei_timer_handler(unsigned long dummy)
80{
81 sn_cpei_handler(-1, NULL, NULL);
82 mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL);
83}
84
85void sn_init_cpei_timer(void)
86{
87 init_timer(&sn_cpei_timer);
88 sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
89 sn_cpei_timer.function = sn_cpei_timer_handler;
90 add_timer(&sn_cpei_timer);
91}
92
93static int
94sn_platform_plat_specific_err_print(const u8 * sect_header, u8 ** oemdata,
95 u64 * oemdata_size)
96{
97 down(&sn_oemdata_mutex);
98 sn_oemdata = oemdata;
99 sn_oemdata_size = oemdata_size;
100 sn_oemdata_bufsize = 0;
101 ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header);
102 up(&sn_oemdata_mutex);
103 return 0;
104}
105
106/* Callback when userspace salinfo wants to decode oem data via the platform
107 * kernel and/or prom.
108 */
109int sn_salinfo_platform_oemdata(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size)
110{
111 efi_guid_t guid = *(efi_guid_t *)sect_header;
112 int valid = 0;
113 *oemdata_size = 0;
114 vfree(*oemdata);
115 *oemdata = NULL;
116 if (efi_guidcmp(guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) {
117 sal_log_plat_specific_err_info_t *psei = (sal_log_plat_specific_err_info_t *)sect_header;
118 valid = psei->valid.oem_data;
119 } else if (efi_guidcmp(guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) {
120 sal_log_mem_dev_err_info_t *mdei = (sal_log_mem_dev_err_info_t *)sect_header;
121 valid = mdei->valid.oem_data;
122 }
123 if (valid)
124 return sn_platform_plat_specific_err_print(sect_header, oemdata, oemdata_size);
125 else
126 return 0;
127}
128
129static int __init sn_salinfo_init(void)
130{
131 salinfo_platform_oemdata = &sn_salinfo_platform_oemdata;
132 return 0;
133}
134
135module_init(sn_salinfo_init)