Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/ia64/sn/kernel/mca.c
10819 views
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-2006 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 <linux/mutex.h>
14
#include <asm/mca.h>
15
#include <asm/sal.h>
16
#include <asm/sn/sn_sal.h>
17
18
/*
19
* Interval for calling SAL to poll for errors that do NOT cause error
20
* interrupts. SAL will raise a CPEI if any errors are present that
21
* need to be logged.
22
*/
23
#define CPEI_INTERVAL (5*HZ)
24
25
struct timer_list sn_cpei_timer;
26
void sn_init_cpei_timer(void);
27
28
/* Printing oemdata from mca uses data that is not passed through SAL, it is
29
* global. Only one user at a time.
30
*/
31
static DEFINE_MUTEX(sn_oemdata_mutex);
32
static u8 **sn_oemdata;
33
static u64 *sn_oemdata_size, sn_oemdata_bufsize;
34
35
/*
36
* print_hook
37
*
38
* This function is the callback routine that SAL calls to log error
39
* info for platform errors. buf is appended to sn_oemdata, resizing as
40
* required.
41
* Note: this is a SAL to OS callback, running under the same rules as the SAL
42
* code. SAL calls are run with preempt disabled so this routine must not
43
* sleep. vmalloc can sleep so print_hook cannot resize the output buffer
44
* itself, instead it must set the required size and return to let the caller
45
* resize the buffer then redrive the SAL call.
46
*/
47
static int print_hook(const char *fmt, ...)
48
{
49
char buf[400];
50
int len;
51
va_list args;
52
va_start(args, fmt);
53
vsnprintf(buf, sizeof(buf), fmt, args);
54
va_end(args);
55
len = strlen(buf);
56
if (*sn_oemdata_size + len <= sn_oemdata_bufsize)
57
memcpy(*sn_oemdata + *sn_oemdata_size, buf, len);
58
*sn_oemdata_size += len;
59
return 0;
60
}
61
62
static void sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
63
{
64
/*
65
* this function's sole purpose is to call SAL when we receive
66
* a CE interrupt from SHUB or when the timer routine decides
67
* we need to call SAL to check for CEs.
68
*/
69
70
/* CALL SAL_LOG_CE */
71
72
ia64_sn_plat_cpei_handler();
73
}
74
75
static void sn_cpei_timer_handler(unsigned long dummy)
76
{
77
sn_cpei_handler(-1, NULL, NULL);
78
mod_timer(&sn_cpei_timer, jiffies + CPEI_INTERVAL);
79
}
80
81
void sn_init_cpei_timer(void)
82
{
83
init_timer(&sn_cpei_timer);
84
sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
85
sn_cpei_timer.function = sn_cpei_timer_handler;
86
add_timer(&sn_cpei_timer);
87
}
88
89
static int
90
sn_platform_plat_specific_err_print(const u8 * sect_header, u8 ** oemdata,
91
u64 * oemdata_size)
92
{
93
mutex_lock(&sn_oemdata_mutex);
94
sn_oemdata = oemdata;
95
sn_oemdata_size = oemdata_size;
96
sn_oemdata_bufsize = 0;
97
*sn_oemdata_size = PAGE_SIZE; /* first guess at how much data will be generated */
98
while (*sn_oemdata_size > sn_oemdata_bufsize) {
99
u8 *newbuf = vmalloc(*sn_oemdata_size);
100
if (!newbuf) {
101
mutex_unlock(&sn_oemdata_mutex);
102
printk(KERN_ERR "%s: unable to extend sn_oemdata\n",
103
__func__);
104
return 1;
105
}
106
vfree(*sn_oemdata);
107
*sn_oemdata = newbuf;
108
sn_oemdata_bufsize = *sn_oemdata_size;
109
*sn_oemdata_size = 0;
110
ia64_sn_plat_specific_err_print(print_hook, (char *)sect_header);
111
}
112
mutex_unlock(&sn_oemdata_mutex);
113
return 0;
114
}
115
116
/* Callback when userspace salinfo wants to decode oem data via the platform
117
* kernel and/or prom.
118
*/
119
int sn_salinfo_platform_oemdata(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size)
120
{
121
efi_guid_t guid = *(efi_guid_t *)sect_header;
122
int valid = 0;
123
*oemdata_size = 0;
124
vfree(*oemdata);
125
*oemdata = NULL;
126
if (efi_guidcmp(guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) {
127
sal_log_plat_specific_err_info_t *psei = (sal_log_plat_specific_err_info_t *)sect_header;
128
valid = psei->valid.oem_data;
129
} else if (efi_guidcmp(guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) {
130
sal_log_mem_dev_err_info_t *mdei = (sal_log_mem_dev_err_info_t *)sect_header;
131
valid = mdei->valid.oem_data;
132
}
133
if (valid)
134
return sn_platform_plat_specific_err_print(sect_header, oemdata, oemdata_size);
135
else
136
return 0;
137
}
138
139
static int __init sn_salinfo_init(void)
140
{
141
if (ia64_platform_is("sn2"))
142
salinfo_platform_oemdata = &sn_salinfo_platform_oemdata;
143
return 0;
144
}
145
146
module_init(sn_salinfo_init)
147
148