Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
x86
kernel
cpu
mcheck
mce-apei.c
Go to the documentation of this file.
1
/*
2
* Bridge between MCE and APEI
3
*
4
* On some machine, corrected memory errors are reported via APEI
5
* generic hardware error source (GHES) instead of corrected Machine
6
* Check. These corrected memory errors can be reported to user space
7
* through /dev/mcelog via faking a corrected Machine Check, so that
8
* the error memory page can be offlined by /sbin/mcelog if the error
9
* count for one page is beyond the threshold.
10
*
11
* For fatal MCE, save MCE record into persistent storage via ERST, so
12
* that the MCE record can be logged after reboot via ERST.
13
*
14
* Copyright 2010 Intel Corp.
15
* Author: Huang Ying <
[email protected]
>
16
*
17
* This program is free software; you can redistribute it and/or
18
* modify it under the terms of the GNU General Public License version
19
* 2 as published by the Free Software Foundation.
20
*
21
* This program is distributed in the hope that it will be useful,
22
* but WITHOUT ANY WARRANTY; without even the implied warranty of
23
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
* GNU General Public License for more details.
25
*
26
* You should have received a copy of the GNU General Public License
27
* along with this program; if not, write to the Free Software
28
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
*/
30
31
#include <linux/export.h>
32
#include <linux/kernel.h>
33
#include <
linux/acpi.h
>
34
#include <
linux/cper.h
>
35
#include <
acpi/apei.h
>
36
#include <asm/mce.h>
37
38
#include "
mce-internal.h
"
39
40
void
apei_mce_report_mem_error
(
int
corrected,
struct
cper_sec_mem_err
*
mem_err
)
41
{
42
struct
mce
m;
43
44
/* Only corrected MC is reported */
45
if
(!corrected || !(mem_err->
validation_bits
&
46
CPER_MEM_VALID_PHYSICAL_ADDRESS
))
47
return
;
48
49
mce_setup
(&m);
50
m.
bank
= 1;
51
/* Fake a memory read corrected error with unknown channel */
52
m.
status
=
MCI_STATUS_VAL
|
MCI_STATUS_EN
|
MCI_STATUS_ADDRV
| 0x9f;
53
m.
addr
= mem_err->
physical_addr
;
54
mce_log
(&m);
55
mce_notify_irq
();
56
}
57
EXPORT_SYMBOL_GPL
(
apei_mce_report_mem_error
);
58
59
#define CPER_CREATOR_MCE \
60
UUID_LE(0x75a574e3, 0x5052, 0x4b29, 0x8a, 0x8e, 0xbe, 0x2c, \
61
0x64, 0x90, 0xb8, 0x9d)
62
#define CPER_SECTION_TYPE_MCE \
63
UUID_LE(0xfe08ffbe, 0x95e4, 0x4be7, 0xbc, 0x73, 0x40, 0x96, \
64
0x04, 0x4a, 0x38, 0xfc)
65
66
/*
67
* CPER specification (in UEFI specification 2.3 appendix N) requires
68
* byte-packed.
69
*/
70
struct
cper_mce_record
{
71
struct
cper_record_header
hdr
;
72
struct
cper_section_descriptor
sec_hdr
;
73
struct
mce
mce
;
74
}
__packed
;
75
76
int
apei_write_mce
(
struct
mce
*
m
)
77
{
78
struct
cper_mce_record
rcd;
79
80
memset
(&rcd, 0,
sizeof
(rcd));
81
memcpy
(rcd.
hdr
.signature,
CPER_SIG_RECORD
,
CPER_SIG_SIZE
);
82
rcd.
hdr
.revision =
CPER_RECORD_REV
;
83
rcd.
hdr
.signature_end =
CPER_SIG_END
;
84
rcd.
hdr
.section_count = 1;
85
rcd.
hdr
.error_severity =
CPER_SEV_FATAL
;
86
/* timestamp, platform_id, partition_id are all invalid */
87
rcd.
hdr
.validation_bits = 0;
88
rcd.
hdr
.record_length =
sizeof
(rcd);
89
rcd.
hdr
.creator_id =
CPER_CREATOR_MCE
;
90
rcd.
hdr
.notification_type =
CPER_NOTIFY_MCE
;
91
rcd.
hdr
.record_id =
cper_next_record_id
();
92
rcd.
hdr
.flags =
CPER_HW_ERROR_FLAGS_PREVERR
;
93
94
rcd.
sec_hdr
.section_offset = (
void
*)&rcd.
mce
- (
void
*)&rcd;
95
rcd.
sec_hdr
.section_length =
sizeof
(rcd.
mce
);
96
rcd.
sec_hdr
.revision =
CPER_SEC_REV
;
97
/* fru_id and fru_text is invalid */
98
rcd.
sec_hdr
.validation_bits = 0;
99
rcd.
sec_hdr
.flags =
CPER_SEC_PRIMARY
;
100
rcd.
sec_hdr
.section_type =
CPER_SECTION_TYPE_MCE
;
101
rcd.
sec_hdr
.section_severity =
CPER_SEV_FATAL
;
102
103
memcpy
(&rcd.
mce
, m,
sizeof
(*m));
104
105
return
erst_write
(&rcd.
hdr
);
106
}
107
108
ssize_t
apei_read_mce
(
struct
mce
*
m
,
u64
*record_id)
109
{
110
struct
cper_mce_record
rcd;
111
int
rc
,
pos
;
112
113
rc =
erst_get_record_id_begin
(&pos);
114
if
(rc)
115
return
rc
;
116
retry
:
117
rc =
erst_get_record_id_next
(&pos, record_id);
118
if
(rc)
119
goto
out
;
120
/* no more record */
121
if
(*record_id ==
APEI_ERST_INVALID_RECORD_ID
)
122
goto
out
;
123
rc =
erst_read
(*record_id, &rcd.
hdr
,
sizeof
(rcd));
124
/* someone else has cleared the record, try next one */
125
if
(rc == -
ENOENT
)
126
goto
retry
;
127
else
if
(rc < 0)
128
goto
out
;
129
/* try to skip other type records in storage */
130
else
if
(rc !=
sizeof
(rcd) ||
131
uuid_le_cmp(rcd.
hdr
.creator_id,
CPER_CREATOR_MCE
))
132
goto
retry
;
133
memcpy
(m, &rcd.
mce
,
sizeof
(*m));
134
rc =
sizeof
(*m);
135
out
:
136
erst_get_record_id_end
();
137
138
return
rc
;
139
}
140
141
/* Check whether there is record in ERST */
142
int
apei_check_mce
(
void
)
143
{
144
return
erst_get_record_count
();
145
}
146
147
int
apei_clear_mce
(
u64
record_id)
148
{
149
return
erst_clear
(record_id);
150
}
Generated on Thu Jan 10 2013 13:20:29 for Linux Kernel by
1.8.2