diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /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.c | 135 |
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 | |||
24 | struct timer_list sn_cpei_timer; | ||
25 | void 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 | */ | ||
30 | static DECLARE_MUTEX(sn_oemdata_mutex); | ||
31 | static u8 **sn_oemdata; | ||
32 | static 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 | */ | ||
41 | static 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 | |||
66 | static 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 | |||
79 | static 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 | |||
85 | void 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 | |||
93 | static int | ||
94 | sn_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 | */ | ||
109 | int 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 | |||
129 | static int __init sn_salinfo_init(void) | ||
130 | { | ||
131 | salinfo_platform_oemdata = &sn_salinfo_platform_oemdata; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | module_init(sn_salinfo_init) | ||