Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
03b6e6e5
Commit
03b6e6e5
authored
Jan 12, 2011
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'apei' into release
parents
9e0c20bc
81e88fdc
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
866 additions
and
92 deletions
+866
-92
Documentation/acpi/apei/output_format.txt
Documentation/acpi/apei/output_format.txt
+122
-0
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/acpi/boot.c
+1
-0
arch/x86/kernel/dumpstack.c
arch/x86/kernel/dumpstack.c
+1
-0
drivers/acpi/apei/apei-internal.h
drivers/acpi/apei/apei-internal.h
+2
-0
drivers/acpi/apei/cper.c
drivers/acpi/apei/cper.c
+311
-0
drivers/acpi/apei/ghes.c
drivers/acpi/apei/ghes.c
+343
-88
include/linux/cper.h
include/linux/cper.h
+82
-4
kernel/panic.c
kernel/panic.c
+1
-0
lib/ioremap.c
lib/ioremap.c
+2
-0
mm/vmalloc.c
mm/vmalloc.c
+1
-0
No files found.
Documentation/acpi/apei/output_format.txt
0 → 100644
View file @
03b6e6e5
APEI output format
~~~~~~~~~~~~~~~~~~
APEI uses printk as hardware error reporting interface, the output
format is as follow.
<error record> :=
APEI generic hardware error status
severity: <integer>, <severity string>
section: <integer>, severity: <integer>, <severity string>
flags: <integer>
<section flags strings>
fru_id: <uuid string>
fru_text: <string>
section_type: <section type string>
<section data>
<severity string>* := recoverable | fatal | corrected | info
<section flags strings># :=
[primary][, containment warning][, reset][, threshold exceeded]\
[, resource not accessible][, latent error]
<section type string> := generic processor error | memory error | \
PCIe error | unknown, <uuid string>
<section data> :=
<generic processor section data> | <memory section data> | \
<pcie section data> | <null>
<generic processor section data> :=
[processor_type: <integer>, <proc type string>]
[processor_isa: <integer>, <proc isa string>]
[error_type: <integer>
<proc error type strings>]
[operation: <integer>, <proc operation string>]
[flags: <integer>
<proc flags strings>]
[level: <integer>]
[version_info: <integer>]
[processor_id: <integer>]
[target_address: <integer>]
[requestor_id: <integer>]
[responder_id: <integer>]
[IP: <integer>]
<proc type string>* := IA32/X64 | IA64
<proc isa string>* := IA32 | IA64 | X64
<processor error type strings># :=
[cache error][, TLB error][, bus error][, micro-architectural error]
<proc operation string>* := unknown or generic | data read | data write | \
instruction execution
<proc flags strings># :=
[restartable][, precise IP][, overflow][, corrected]
<memory section data> :=
[error_status: <integer>]
[physical_address: <integer>]
[physical_address_mask: <integer>]
[node: <integer>]
[card: <integer>]
[module: <integer>]
[bank: <integer>]
[device: <integer>]
[row: <integer>]
[column: <integer>]
[bit_position: <integer>]
[requestor_id: <integer>]
[responder_id: <integer>]
[target_id: <integer>]
[error_type: <integer>, <mem error type string>]
<mem error type string>* :=
unknown | no error | single-bit ECC | multi-bit ECC | \
single-symbol chipkill ECC | multi-symbol chipkill ECC | master abort | \
target abort | parity error | watchdog timeout | invalid address | \
mirror Broken | memory sparing | scrub corrected error | \
scrub uncorrected error
<pcie section data> :=
[port_type: <integer>, <pcie port type string>]
[version: <integer>.<integer>]
[command: <integer>, status: <integer>]
[device_id: <integer>:<integer>:<integer>.<integer>
slot: <integer>
secondary_bus: <integer>
vendor_id: <integer>, device_id: <integer>
class_code: <integer>]
[serial number: <integer>, <integer>]
[bridge: secondary_status: <integer>, control: <integer>]
<pcie port type string>* := PCIe end point | legacy PCI end point | \
unknown | unknown | root port | upstream switch port | \
downstream switch port | PCIe to PCI/PCI-X bridge | \
PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \
root complex event collector
Where, [] designate corresponding content is optional
All <field string> description with * has the following format:
field: <integer>, <field string>
Where value of <integer> should be the position of "string" in <field
string> description. Otherwise, <field string> will be "unknown".
All <field strings> description with # has the following format:
field: <integer>
<field strings>
Where each string in <fields strings> corresponding to one set bit of
<integer>. The bit position is the position of "string" in <field
strings> description.
For more detailed explanation of every field, please refer to UEFI
specification version 2.3 or later, section Appendix N: Common
Platform Error Record.
arch/x86/kernel/acpi/boot.c
View file @
03b6e6e5
...
...
@@ -504,6 +504,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
return
0
;
}
EXPORT_SYMBOL_GPL
(
acpi_gsi_to_irq
);
int
acpi_isa_irq_to_gsi
(
unsigned
isa_irq
,
u32
*
gsi
)
{
...
...
arch/x86/kernel/dumpstack.c
View file @
03b6e6e5
...
...
@@ -240,6 +240,7 @@ unsigned __kprobes long oops_begin(void)
bust_spinlocks
(
1
);
return
flags
;
}
EXPORT_SYMBOL_GPL
(
oops_begin
);
void
__kprobes
oops_end
(
unsigned
long
flags
,
struct
pt_regs
*
regs
,
int
signr
)
{
...
...
drivers/acpi/apei/apei-internal.h
View file @
03b6e6e5
...
...
@@ -109,6 +109,8 @@ static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
return
sizeof
(
*
estatus
)
+
estatus
->
data_length
;
}
void
apei_estatus_print
(
const
char
*
pfx
,
const
struct
acpi_hest_generic_status
*
estatus
);
int
apei_estatus_check_header
(
const
struct
acpi_hest_generic_status
*
estatus
);
int
apei_estatus_check
(
const
struct
acpi_hest_generic_status
*
estatus
);
#endif
drivers/acpi/apei/cper.c
View file @
03b6e6e5
...
...
@@ -46,6 +46,317 @@ u64 cper_next_record_id(void)
}
EXPORT_SYMBOL_GPL
(
cper_next_record_id
);
static
const
char
*
cper_severity_strs
[]
=
{
"recoverable"
,
"fatal"
,
"corrected"
,
"info"
,
};
static
const
char
*
cper_severity_str
(
unsigned
int
severity
)
{
return
severity
<
ARRAY_SIZE
(
cper_severity_strs
)
?
cper_severity_strs
[
severity
]
:
"unknown"
;
}
/*
* cper_print_bits - print strings for set bits
* @pfx: prefix for each line, including log level and prefix string
* @bits: bit mask
* @strs: string array, indexed by bit position
* @strs_size: size of the string array: @strs
*
* For each set bit in @bits, print the corresponding string in @strs.
* If the output length is longer than 80, multiple line will be
* printed, with @pfx is printed at the beginning of each line.
*/
static
void
cper_print_bits
(
const
char
*
pfx
,
unsigned
int
bits
,
const
char
*
strs
[],
unsigned
int
strs_size
)
{
int
i
,
len
=
0
;
const
char
*
str
;
char
buf
[
84
];
for
(
i
=
0
;
i
<
strs_size
;
i
++
)
{
if
(
!
(
bits
&
(
1U
<<
i
)))
continue
;
str
=
strs
[
i
];
if
(
len
&&
len
+
strlen
(
str
)
+
2
>
80
)
{
printk
(
"%s
\n
"
,
buf
);
len
=
0
;
}
if
(
!
len
)
len
=
snprintf
(
buf
,
sizeof
(
buf
),
"%s%s"
,
pfx
,
str
);
else
len
+=
snprintf
(
buf
+
len
,
sizeof
(
buf
)
-
len
,
", %s"
,
str
);
}
if
(
len
)
printk
(
"%s
\n
"
,
buf
);
}
static
const
char
*
cper_proc_type_strs
[]
=
{
"IA32/X64"
,
"IA64"
,
};
static
const
char
*
cper_proc_isa_strs
[]
=
{
"IA32"
,
"IA64"
,
"X64"
,
};
static
const
char
*
cper_proc_error_type_strs
[]
=
{
"cache error"
,
"TLB error"
,
"bus error"
,
"micro-architectural error"
,
};
static
const
char
*
cper_proc_op_strs
[]
=
{
"unknown or generic"
,
"data read"
,
"data write"
,
"instruction execution"
,
};
static
const
char
*
cper_proc_flag_strs
[]
=
{
"restartable"
,
"precise IP"
,
"overflow"
,
"corrected"
,
};
static
void
cper_print_proc_generic
(
const
char
*
pfx
,
const
struct
cper_sec_proc_generic
*
proc
)
{
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_TYPE
)
printk
(
"%s""processor_type: %d, %s
\n
"
,
pfx
,
proc
->
proc_type
,
proc
->
proc_type
<
ARRAY_SIZE
(
cper_proc_type_strs
)
?
cper_proc_type_strs
[
proc
->
proc_type
]
:
"unknown"
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_ISA
)
printk
(
"%s""processor_isa: %d, %s
\n
"
,
pfx
,
proc
->
proc_isa
,
proc
->
proc_isa
<
ARRAY_SIZE
(
cper_proc_isa_strs
)
?
cper_proc_isa_strs
[
proc
->
proc_isa
]
:
"unknown"
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_ERROR_TYPE
)
{
printk
(
"%s""error_type: 0x%02x
\n
"
,
pfx
,
proc
->
proc_error_type
);
cper_print_bits
(
pfx
,
proc
->
proc_error_type
,
cper_proc_error_type_strs
,
ARRAY_SIZE
(
cper_proc_error_type_strs
));
}
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_OPERATION
)
printk
(
"%s""operation: %d, %s
\n
"
,
pfx
,
proc
->
operation
,
proc
->
operation
<
ARRAY_SIZE
(
cper_proc_op_strs
)
?
cper_proc_op_strs
[
proc
->
operation
]
:
"unknown"
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_FLAGS
)
{
printk
(
"%s""flags: 0x%02x
\n
"
,
pfx
,
proc
->
flags
);
cper_print_bits
(
pfx
,
proc
->
flags
,
cper_proc_flag_strs
,
ARRAY_SIZE
(
cper_proc_flag_strs
));
}
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_LEVEL
)
printk
(
"%s""level: %d
\n
"
,
pfx
,
proc
->
level
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_VERSION
)
printk
(
"%s""version_info: 0x%016llx
\n
"
,
pfx
,
proc
->
cpu_version
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_ID
)
printk
(
"%s""processor_id: 0x%016llx
\n
"
,
pfx
,
proc
->
proc_id
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_TARGET_ADDRESS
)
printk
(
"%s""target_address: 0x%016llx
\n
"
,
pfx
,
proc
->
target_addr
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_REQUESTOR_ID
)
printk
(
"%s""requestor_id: 0x%016llx
\n
"
,
pfx
,
proc
->
requestor_id
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_RESPONDER_ID
)
printk
(
"%s""responder_id: 0x%016llx
\n
"
,
pfx
,
proc
->
responder_id
);
if
(
proc
->
validation_bits
&
CPER_PROC_VALID_IP
)
printk
(
"%s""IP: 0x%016llx
\n
"
,
pfx
,
proc
->
ip
);
}
static
const
char
*
cper_mem_err_type_strs
[]
=
{
"unknown"
,
"no error"
,
"single-bit ECC"
,
"multi-bit ECC"
,
"single-symbol chipkill ECC"
,
"multi-symbol chipkill ECC"
,
"master abort"
,
"target abort"
,
"parity error"
,
"watchdog timeout"
,
"invalid address"
,
"mirror Broken"
,
"memory sparing"
,
"scrub corrected error"
,
"scrub uncorrected error"
,
};
static
void
cper_print_mem
(
const
char
*
pfx
,
const
struct
cper_sec_mem_err
*
mem
)
{
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_ERROR_STATUS
)
printk
(
"%s""error_status: 0x%016llx
\n
"
,
pfx
,
mem
->
error_status
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_PHYSICAL_ADDRESS
)
printk
(
"%s""physical_address: 0x%016llx
\n
"
,
pfx
,
mem
->
physical_addr
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK
)
printk
(
"%s""physical_address_mask: 0x%016llx
\n
"
,
pfx
,
mem
->
physical_addr_mask
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_NODE
)
printk
(
"%s""node: %d
\n
"
,
pfx
,
mem
->
node
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_CARD
)
printk
(
"%s""card: %d
\n
"
,
pfx
,
mem
->
card
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_MODULE
)
printk
(
"%s""module: %d
\n
"
,
pfx
,
mem
->
module
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_BANK
)
printk
(
"%s""bank: %d
\n
"
,
pfx
,
mem
->
bank
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_DEVICE
)
printk
(
"%s""device: %d
\n
"
,
pfx
,
mem
->
device
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_ROW
)
printk
(
"%s""row: %d
\n
"
,
pfx
,
mem
->
row
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_COLUMN
)
printk
(
"%s""column: %d
\n
"
,
pfx
,
mem
->
column
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_BIT_POSITION
)
printk
(
"%s""bit_position: %d
\n
"
,
pfx
,
mem
->
bit_pos
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_REQUESTOR_ID
)
printk
(
"%s""requestor_id: 0x%016llx
\n
"
,
pfx
,
mem
->
requestor_id
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_RESPONDER_ID
)
printk
(
"%s""responder_id: 0x%016llx
\n
"
,
pfx
,
mem
->
responder_id
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_TARGET_ID
)
printk
(
"%s""target_id: 0x%016llx
\n
"
,
pfx
,
mem
->
target_id
);
if
(
mem
->
validation_bits
&
CPER_MEM_VALID_ERROR_TYPE
)
{
u8
etype
=
mem
->
error_type
;
printk
(
"%s""error_type: %d, %s
\n
"
,
pfx
,
etype
,
etype
<
ARRAY_SIZE
(
cper_mem_err_type_strs
)
?
cper_mem_err_type_strs
[
etype
]
:
"unknown"
);
}
}
static
const
char
*
cper_pcie_port_type_strs
[]
=
{
"PCIe end point"
,
"legacy PCI end point"
,
"unknown"
,
"unknown"
,
"root port"
,
"upstream switch port"
,
"downstream switch port"
,
"PCIe to PCI/PCI-X bridge"
,
"PCI/PCI-X to PCIe bridge"
,
"root complex integrated endpoint device"
,
"root complex event collector"
,
};
static
void
cper_print_pcie
(
const
char
*
pfx
,
const
struct
cper_sec_pcie
*
pcie
)
{
if
(
pcie
->
validation_bits
&
CPER_PCIE_VALID_PORT_TYPE
)
printk
(
"%s""port_type: %d, %s
\n
"
,
pfx
,
pcie
->
port_type
,
pcie
->
port_type
<
ARRAY_SIZE
(
cper_pcie_port_type_strs
)
?
cper_pcie_port_type_strs
[
pcie
->
port_type
]
:
"unknown"
);
if
(
pcie
->
validation_bits
&
CPER_PCIE_VALID_VERSION
)
printk
(
"%s""version: %d.%d
\n
"
,
pfx
,
pcie
->
version
.
major
,
pcie
->
version
.
minor
);
if
(
pcie
->
validation_bits
&
CPER_PCIE_VALID_COMMAND_STATUS
)
printk
(
"%s""command: 0x%04x, status: 0x%04x
\n
"
,
pfx
,
pcie
->
command
,
pcie
->
status
);
if
(
pcie
->
validation_bits
&
CPER_PCIE_VALID_DEVICE_ID
)
{
const
__u8
*
p
;
printk
(
"%s""device_id: %04x:%02x:%02x.%x
\n
"
,
pfx
,
pcie
->
device_id
.
segment
,
pcie
->
device_id
.
bus
,
pcie
->
device_id
.
device
,
pcie
->
device_id
.
function
);
printk
(
"%s""slot: %d
\n
"
,
pfx
,
pcie
->
device_id
.
slot
>>
CPER_PCIE_SLOT_SHIFT
);
printk
(
"%s""secondary_bus: 0x%02x
\n
"
,
pfx
,
pcie
->
device_id
.
secondary_bus
);
printk
(
"%s""vendor_id: 0x%04x, device_id: 0x%04x
\n
"
,
pfx
,
pcie
->
device_id
.
vendor_id
,
pcie
->
device_id
.
device_id
);
p
=
pcie
->
device_id
.
class_code
;
printk
(
"%s""class_code: %02x%02x%02x
\n
"
,
pfx
,
p
[
0
],
p
[
1
],
p
[
2
]);
}
if
(
pcie
->
validation_bits
&
CPER_PCIE_VALID_SERIAL_NUMBER
)
printk
(
"%s""serial number: 0x%04x, 0x%04x
\n
"
,
pfx
,
pcie
->
serial_number
.
lower
,
pcie
->
serial_number
.
upper
);
if
(
pcie
->
validation_bits
&
CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS
)
printk
(
"%s""bridge: secondary_status: 0x%04x, control: 0x%04x
\n
"
,
pfx
,
pcie
->
bridge
.
secondary_status
,
pcie
->
bridge
.
control
);
}
static
const
char
*
apei_estatus_section_flag_strs
[]
=
{
"primary"
,
"containment warning"
,
"reset"
,
"threshold exceeded"
,
"resource not accessible"
,
"latent error"
,
};
static
void
apei_estatus_print_section
(
const
char
*
pfx
,
const
struct
acpi_hest_generic_data
*
gdata
,
int
sec_no
)
{
uuid_le
*
sec_type
=
(
uuid_le
*
)
gdata
->
section_type
;
__u16
severity
;
severity
=
gdata
->
error_severity
;
printk
(
"%s""section: %d, severity: %d, %s
\n
"
,
pfx
,
sec_no
,
severity
,
cper_severity_str
(
severity
));
printk
(
"%s""flags: 0x%02x
\n
"
,
pfx
,
gdata
->
flags
);
cper_print_bits
(
pfx
,
gdata
->
flags
,
apei_estatus_section_flag_strs
,
ARRAY_SIZE
(
apei_estatus_section_flag_strs
));
if
(
gdata
->
validation_bits
&
CPER_SEC_VALID_FRU_ID
)
printk
(
"%s""fru_id: %pUl
\n
"
,
pfx
,
(
uuid_le
*
)
gdata
->
fru_id
);
if
(
gdata
->
validation_bits
&
CPER_SEC_VALID_FRU_TEXT
)
printk
(
"%s""fru_text: %.20s
\n
"
,
pfx
,
gdata
->
fru_text
);
if
(
!
uuid_le_cmp
(
*
sec_type
,
CPER_SEC_PROC_GENERIC
))
{
struct
cper_sec_proc_generic
*
proc_err
=
(
void
*
)(
gdata
+
1
);
printk
(
"%s""section_type: general processor error
\n
"
,
pfx
);
if
(
gdata
->
error_data_length
>=
sizeof
(
*
proc_err
))
cper_print_proc_generic
(
pfx
,
proc_err
);
else
goto
err_section_too_small
;
}
else
if
(
!
uuid_le_cmp
(
*
sec_type
,
CPER_SEC_PLATFORM_MEM
))
{
struct
cper_sec_mem_err
*
mem_err
=
(
void
*
)(
gdata
+
1
);
printk
(
"%s""section_type: memory error
\n
"
,
pfx
);
if
(
gdata
->
error_data_length
>=
sizeof
(
*
mem_err
))
cper_print_mem
(
pfx
,
mem_err
);
else
goto
err_section_too_small
;
}
else
if
(
!
uuid_le_cmp
(
*
sec_type
,
CPER_SEC_PCIE
))
{
struct
cper_sec_pcie
*
pcie
=
(
void
*
)(
gdata
+
1
);
printk
(
"%s""section_type: PCIe error
\n
"
,
pfx
);
if
(
gdata
->
error_data_length
>=
sizeof
(
*
pcie
))
cper_print_pcie
(
pfx
,
pcie
);
else
goto
err_section_too_small
;
}
else
printk
(
"%s""section type: unknown, %pUl
\n
"
,
pfx
,
sec_type
);
return
;
err_section_too_small:
pr_err
(
FW_WARN
"error section length is too small
\n
"
);
}
void
apei_estatus_print
(
const
char
*
pfx
,
const
struct
acpi_hest_generic_status
*
estatus
)
{
struct
acpi_hest_generic_data
*
gdata
;
unsigned
int
data_len
,
gedata_len
;
int
sec_no
=
0
;
__u16
severity
;
printk
(
"%s""APEI generic hardware error status
\n
"
,
pfx
);
severity
=
estatus
->
error_severity
;
printk
(
"%s""severity: %d, %s
\n
"
,
pfx
,
severity
,
cper_severity_str
(
severity
));
data_len
=
estatus
->
data_length
;
gdata
=
(
struct
acpi_hest_generic_data
*
)(
estatus
+
1
);
while
(
data_len
>
sizeof
(
*
gdata
))
{
gedata_len
=
gdata
->
error_data_length
;
apei_estatus_print_section
(
pfx
,
gdata
,
sec_no
);
data_len
-=
gedata_len
+
sizeof
(
*
gdata
);
sec_no
++
;
}
}
EXPORT_SYMBOL_GPL
(
apei_estatus_print
);
int
apei_estatus_check_header
(
const
struct
acpi_hest_generic_status
*
estatus
)
{
if
(
estatus
->
data_length
&&
...
...
drivers/acpi/apei/ghes.c
View file @
03b6e6e5
...
...
@@ -12,10 +12,6 @@
* For more information about Generic Hardware Error Source, please
* refer to ACPI Specification version 4.0, section 17.3.2.6
*
* Now, only SCI notification type and memory errors are
* supported. More notification type and hardware error type will be
* added later.
*
* Copyright 2010 Intel Corp.
* Author: Huang Ying <ying.huang@intel.com>
*
...
...
@@ -39,14 +35,18 @@
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/cper.h>
#include <linux/kdebug.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/ratelimit.h>
#include <linux/vmalloc.h>
#include <acpi/apei.h>
#include <acpi/atomicio.h>
#include <acpi/hed.h>
#include <asm/mce.h>
#include <asm/tlbflush.h>
#include "apei-internal.h"
...
...
@@ -55,42 +55,131 @@
#define GHES_ESTATUS_MAX_SIZE 65536
/*
* One struct ghes is created for each generic hardware error
* source.
*
* One struct ghes is created for each generic hardware error source.
* It provides the context for APEI hardware error timer/IRQ/SCI/NMI
* handler. Handler for one generic hardware error source is only
* triggered after the previous one is done. So handler can uses
* struct ghes without locking.
* handler.
*
* estatus: memory buffer for error status block, allocated during
* HEST parsing.
*/
#define GHES_TO_CLEAR 0x0001
#define GHES_EXITING 0x0002
struct
ghes
{
struct
acpi_hest_generic
*
generic
;
struct
acpi_hest_generic_status
*
estatus
;
struct
list_head
list
;
u64
buffer_paddr
;
unsigned
long
flags
;
union
{
struct
list_head
list
;
struct
timer_list
timer
;
unsigned
int
irq
;
};
};
static
int
ghes_panic_timeout
__read_mostly
=
30
;
/*
* Error source lists, one list for each notification method. The
* members in lists are struct ghes.
* All error sources notified with SCI shares one notifier function,
* so they need to be linked and checked one by one. This is applied
* to NMI too.
*
* The list members are only added in HEST parsing and deleted during
* module_exit, that is, single-threaded. So no lock is needed for
* that.
*
* But the mutual exclusion is needed between members adding/deleting
* and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is
* used for that.
* RCU is used for these lists, so ghes_list_mutex is only used for
* list changing, not for traversing.
*/
static
LIST_HEAD
(
ghes_sci
);
static
LIST_HEAD
(
ghes_nmi
);
static
DEFINE_MUTEX
(
ghes_list_mutex
);
/*
* NMI may be triggered on any CPU, so ghes_nmi_lock is used for
* mutual exclusion.
*/
static
DEFINE_RAW_SPINLOCK
(
ghes_nmi_lock
);
/*
* Because the memory area used to transfer hardware error information
* from BIOS to Linux can be determined only in NMI, IRQ or timer
* handler, but general ioremap can not be used in atomic context, so
* a special version of atomic ioremap is implemented for that.
*/
/*
* Two virtual pages are used, one for NMI context, the other for
* IRQ/PROCESS context
*/
#define GHES_IOREMAP_PAGES 2
#define GHES_IOREMAP_NMI_PAGE(base) (base)
#define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE)
/* virtual memory area for atomic ioremap */
static
struct
vm_struct
*
ghes_ioremap_area
;
/*
* These 2 spinlock is used to prevent atomic ioremap virtual memory
* area from being mapped simultaneously.
*/
static
DEFINE_RAW_SPINLOCK
(
ghes_ioremap_lock_nmi
);
static
DEFINE_SPINLOCK
(
ghes_ioremap_lock_irq
);
static
int
ghes_ioremap_init
(
void
)
{
ghes_ioremap_area
=
__get_vm_area
(
PAGE_SIZE
*
GHES_IOREMAP_PAGES
,
VM_IOREMAP
,
VMALLOC_START
,
VMALLOC_END
);
if
(
!
ghes_ioremap_area
)
{
pr_err
(
GHES_PFX
"Failed to allocate virtual memory area for atomic ioremap.
\n
"
);
return
-
ENOMEM
;
}
return
0
;
}
static
void
ghes_ioremap_exit
(
void
)
{
free_vm_area
(
ghes_ioremap_area
);
}
static
void
__iomem
*
ghes_ioremap_pfn_nmi
(
u64
pfn
)
{
unsigned
long
vaddr
;
vaddr
=
(
unsigned
long
)
GHES_IOREMAP_NMI_PAGE
(
ghes_ioremap_area
->
addr
);
ioremap_page_range
(
vaddr
,
vaddr
+
PAGE_SIZE
,
pfn
<<
PAGE_SHIFT
,
PAGE_KERNEL
);
return
(
void
__iomem
*
)
vaddr
;
}
static
void
__iomem
*
ghes_ioremap_pfn_irq
(
u64
pfn
)
{
unsigned
long
vaddr
;
vaddr
=
(
unsigned
long
)
GHES_IOREMAP_IRQ_PAGE
(
ghes_ioremap_area
->
addr
);
ioremap_page_range
(
vaddr
,
vaddr
+
PAGE_SIZE
,
pfn
<<
PAGE_SHIFT
,
PAGE_KERNEL
);
return
(
void
__iomem
*
)
vaddr
;
}
static
void
ghes_iounmap_nmi
(
void
__iomem
*
vaddr_ptr
)
{
unsigned
long
vaddr
=
(
unsigned
long
__force
)
vaddr_ptr
;
void
*
base
=
ghes_ioremap_area
->
addr
;
BUG_ON
(
vaddr
!=
(
unsigned
long
)
GHES_IOREMAP_NMI_PAGE
(
base
));
unmap_kernel_range_noflush
(
vaddr
,
PAGE_SIZE
);
__flush_tlb_one
(
vaddr
);
}
static
void
ghes_iounmap_irq
(
void
__iomem
*
vaddr_ptr
)
{
unsigned
long
vaddr
=
(
unsigned
long
__force
)
vaddr_ptr
;
void
*
base
=
ghes_ioremap_area
->
addr
;
BUG_ON
(
vaddr
!=
(
unsigned
long
)
GHES_IOREMAP_IRQ_PAGE
(
base
));
unmap_kernel_range_noflush
(
vaddr
,
PAGE_SIZE
);
__flush_tlb_one
(
vaddr
);
}
static
struct
ghes
*
ghes_new
(
struct
acpi_hest_generic
*
generic
)
{
struct
ghes
*
ghes
;
...
...
@@ -101,7 +190,6 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
if
(
!
ghes
)
return
ERR_PTR
(
-
ENOMEM
);
ghes
->
generic
=
generic
;
INIT_LIST_HEAD
(
&
ghes
->
list
);
rc
=
acpi_pre_map_gar
(
&
generic
->
error_status_address
);
if
(
rc
)
goto
err_free
;
...
...
@@ -158,22 +246,41 @@ static inline int ghes_severity(int severity)
}
}
/* SCI handler run in work queue, so ioremap can be used here */
static
int
ghes_copy_tofrom_phys
(
void
*
buffer
,
u64
paddr
,
u32
len
,
int
from_phys
)
static
void
ghes_copy_tofrom_phys
(
void
*
buffer
,
u64
paddr
,
u32
len
,
int
from_phys
)
{
void
*
vaddr
;
vaddr
=
ioremap_cache
(
paddr
,
len
);
if
(
!
vaddr
)
return
-
ENOMEM
;
if
(
from_phys
)
memcpy
(
buffer
,
vaddr
,
len
);
else
memcpy
(
vaddr
,
buffer
,
len
);
iounmap
(
vaddr
);
return
0
;
void
__iomem
*
vaddr
;
unsigned
long
flags
=
0
;
int
in_nmi
=
in_nmi
();
u64
offset
;
u32
trunk
;
while
(
len
>
0
)
{
offset
=
paddr
-
(
paddr
&
PAGE_MASK
);
if
(
in_nmi
)
{
raw_spin_lock
(
&
ghes_ioremap_lock_nmi
);
vaddr
=
ghes_ioremap_pfn_nmi
(
paddr
>>
PAGE_SHIFT
);
}
else
{
spin_lock_irqsave
(
&
ghes_ioremap_lock_irq
,
flags
);
vaddr
=
ghes_ioremap_pfn_irq
(
paddr
>>
PAGE_SHIFT
);
}
trunk
=
PAGE_SIZE
-
offset
;
trunk
=
min
(
trunk
,
len
);
if
(
from_phys
)
memcpy_fromio
(
buffer
,
vaddr
+
offset
,
trunk
);
else
memcpy_toio
(
vaddr
+
offset
,
buffer
,
trunk
);
len
-=
trunk
;
paddr
+=
trunk
;
buffer
+=
trunk
;
if
(
in_nmi
)
{
ghes_iounmap_nmi
(
vaddr
);
raw_spin_unlock
(
&
ghes_ioremap_lock_nmi
);
}
else
{
ghes_iounmap_irq
(
vaddr
);
spin_unlock_irqrestore
(
&
ghes_ioremap_lock_irq
,
flags
);
}
}
}
static
int
ghes_read_estatus
(
struct
ghes
*
ghes
,
int
silent
)
...
...
@@ -194,10 +301,8 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
if
(
!
buf_paddr
)
return
-
ENOENT
;
rc
=
ghes_copy_tofrom_phys
(
ghes
->
estatus
,
buf_paddr
,
sizeof
(
*
ghes
->
estatus
),
1
);
if
(
rc
)
return
rc
;
ghes_copy_tofrom_phys
(
ghes
->
estatus
,
buf_paddr
,
sizeof
(
*
ghes
->
estatus
),
1
);
if
(
!
ghes
->
estatus
->
block_status
)
return
-
ENOENT
;
...
...
@@ -212,17 +317,15 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
goto
err_read_block
;
if
(
apei_estatus_check_header
(
ghes
->
estatus
))
goto
err_read_block
;
rc
=
ghes_copy_tofrom_phys
(
ghes
->
estatus
+
1
,
buf_paddr
+
sizeof
(
*
ghes
->
estatus
),
len
-
sizeof
(
*
ghes
->
estatus
),
1
);
if
(
rc
)
return
rc
;
ghes_copy_tofrom_phys
(
ghes
->
estatus
+
1
,
buf_paddr
+
sizeof
(
*
ghes
->
estatus
),
len
-
sizeof
(
*
ghes
->
estatus
),
1
);
if
(
apei_estatus_check
(
ghes
->
estatus
))
goto
err_read_block
;
rc
=
0
;
err_read_block:
if
(
rc
&&
!
silent
)
if
(
rc
&&
!
silent
&&
printk_ratelimit
()
)
pr_warning
(
FW_WARN
GHES_PFX
"Failed to read error status block!
\n
"
);
return
rc
;
...
...
@@ -255,11 +358,26 @@ static void ghes_do_proc(struct ghes *ghes)
}
#endif
}
}
if
(
!
processed
&&
printk_ratelimit
())
pr_warning
(
GHES_PFX
"Unknown error record from generic hardware error source: %d
\n
"
,
ghes
->
generic
->
header
.
source_id
);
static
void
ghes_print_estatus
(
const
char
*
pfx
,
struct
ghes
*
ghes
)
{
/* Not more than 2 messages every 5 seconds */
static
DEFINE_RATELIMIT_STATE
(
ratelimit
,
5
*
HZ
,
2
);
if
(
pfx
==
NULL
)
{
if
(
ghes_severity
(
ghes
->
estatus
->
error_severity
)
<=
GHES_SEV_CORRECTED
)
pfx
=
KERN_WARNING
HW_ERR
;
else
pfx
=
KERN_ERR
HW_ERR
;
}
if
(
__ratelimit
(
&
ratelimit
))
{
printk
(
"%s""Hardware error from APEI Generic Hardware Error Source: %d
\n
"
,
pfx
,
ghes
->
generic
->
header
.
source_id
);
apei_estatus_print
(
pfx
,
ghes
->
estatus
);
}
}
static
int
ghes_proc
(
struct
ghes
*
ghes
)
...
...
@@ -269,6 +387,7 @@ static int ghes_proc(struct ghes *ghes)
rc
=
ghes_read_estatus
(
ghes
,
0
);
if
(
rc
)
goto
out
;
ghes_print_estatus
(
NULL
,
ghes
);
ghes_do_proc
(
ghes
);
out:
...
...
@@ -276,6 +395,42 @@ static int ghes_proc(struct ghes *ghes)
return
0
;
}
static
void
ghes_add_timer
(
struct
ghes
*
ghes
)
{
struct
acpi_hest_generic
*
g
=
ghes
->
generic
;
unsigned
long
expire
;
if
(
!
g
->
notify
.
poll_interval
)
{
pr_warning
(
FW_WARN
GHES_PFX
"Poll interval is 0 for generic hardware error source: %d, disabled.
\n
"
,
g
->
header
.
source_id
);
return
;
}
expire
=
jiffies
+
msecs_to_jiffies
(
g
->
notify
.
poll_interval
);
ghes
->
timer
.
expires
=
round_jiffies_relative
(
expire
);
add_timer
(
&
ghes
->
timer
);
}
static
void
ghes_poll_func
(
unsigned
long
data
)
{
struct
ghes
*
ghes
=
(
void
*
)
data
;
ghes_proc
(
ghes
);
if
(
!
(
ghes
->
flags
&
GHES_EXITING
))
ghes_add_timer
(
ghes
);
}
static
irqreturn_t
ghes_irq_func
(
int
irq
,
void
*
data
)
{
struct
ghes
*
ghes
=
data
;
int
rc
;
rc
=
ghes_proc
(
ghes
);
if
(
rc
)
return
IRQ_NONE
;
return
IRQ_HANDLED
;
}
static
int
ghes_notify_sci
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
data
)
{
...
...
@@ -292,10 +447,63 @@ static int ghes_notify_sci(struct notifier_block *this,
return
ret
;
}
static
int
ghes_notify_nmi
(
struct
notifier_block
*
this
,
unsigned
long
cmd
,
void
*
data
)
{
struct
ghes
*
ghes
,
*
ghes_global
=
NULL
;
int
sev
,
sev_global
=
-
1
;
int
ret
=
NOTIFY_DONE
;
if
(
cmd
!=
DIE_NMI
)
return
ret
;
raw_spin_lock
(
&
ghes_nmi_lock
);
list_for_each_entry_rcu
(
ghes
,
&
ghes_nmi
,
list
)
{
if
(
ghes_read_estatus
(
ghes
,
1
))
{
ghes_clear_estatus
(
ghes
);
continue
;
}
sev
=
ghes_severity
(
ghes
->
estatus
->
error_severity
);
if
(
sev
>
sev_global
)
{
sev_global
=
sev
;
ghes_global
=
ghes
;
}
ret
=
NOTIFY_STOP
;
}
if
(
ret
==
NOTIFY_DONE
)
goto
out
;
if
(
sev_global
>=
GHES_SEV_PANIC
)
{
oops_begin
();
ghes_print_estatus
(
KERN_EMERG
HW_ERR
,
ghes_global
);
/* reboot to log the error! */
if
(
panic_timeout
==
0
)
panic_timeout
=
ghes_panic_timeout
;
panic
(
"Fatal hardware error!"
);
}
list_for_each_entry_rcu
(
ghes
,
&
ghes_nmi
,
list
)
{
if
(
!
(
ghes
->
flags
&
GHES_TO_CLEAR
))
continue
;
/* Do not print estatus because printk is not NMI safe */
ghes_do_proc
(
ghes
);
ghes_clear_estatus
(
ghes
);
}
out:
raw_spin_unlock
(
&
ghes_nmi_lock
);
return
ret
;
}
static
struct
notifier_block
ghes_notifier_sci
=
{
.
notifier_call
=
ghes_notify_sci
,
};
static
struct
notifier_block
ghes_notifier_nmi
=
{
.
notifier_call
=
ghes_notify_nmi
,
};
static
int
__devinit
ghes_probe
(
struct
platform_device
*
ghes_dev
)
{
struct
acpi_hest_generic
*
generic
;
...
...
@@ -306,18 +514,27 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
if
(
!
generic
->
enabled
)
return
-
ENODEV
;
if
(
generic
->
error_block_length
<
sizeof
(
struct
acpi_hest_generic_status
))
{
pr_warning
(
FW_BUG
GHES_PFX
"Invalid error block length: %u for generic hardware error source: %d
\n
"
,
generic
->
error_block_length
,
switch
(
generic
->
notify
.
type
)
{
case
ACPI_HEST_NOTIFY_POLLED
:
case
ACPI_HEST_NOTIFY_EXTERNAL
:
case
ACPI_HEST_NOTIFY_SCI
:
case
ACPI_HEST_NOTIFY_NMI
:
break
;
case
ACPI_HEST_NOTIFY_LOCAL
:
pr_warning
(
GHES_PFX
"Generic hardware error source: %d notified via local interrupt is not supported!
\n
"
,
generic
->
header
.
source_id
);
goto
err
;
default:
pr_warning
(
FW_WARN
GHES_PFX
"Unknown notification type: %u for generic hardware error source: %d
\n
"
,
generic
->
notify
.
type
,
generic
->
header
.
source_id
);
goto
err
;
}
if
(
generic
->
records_to_preallocate
==
0
)
{
pr_warning
(
FW_BUG
GHES_PFX
"Invalid records to preallocate: %u for generic hardware error source: %d
\n
"
,
generic
->
records_to_preallocate
,
rc
=
-
EIO
;
if
(
generic
->
error_block_length
<
sizeof
(
struct
acpi_hest_generic_status
))
{
pr_warning
(
FW_BUG
GHES_PFX
"Invalid error block length: %u for generic hardware error source: %d
\n
"
,
generic
->
error_block_length
,
generic
->
header
.
source_id
);
goto
err
;
}
...
...
@@ -327,38 +544,43 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
ghes
=
NULL
;
goto
err
;
}
if
(
generic
->
notify
.
type
==
ACPI_HEST_NOTIFY_SCI
)
{
switch
(
generic
->
notify
.
type
)
{
case
ACPI_HEST_NOTIFY_POLLED
:
ghes
->
timer
.
function
=
ghes_poll_func
;
ghes
->
timer
.
data
=
(
unsigned
long
)
ghes
;
init_timer_deferrable
(
&
ghes
->
timer
);
ghes_add_timer
(
ghes
);
break
;
case
ACPI_HEST_NOTIFY_EXTERNAL
:
/* External interrupt vector is GSI */
if
(
acpi_gsi_to_irq
(
generic
->
notify
.
vector
,
&
ghes
->
irq
))
{
pr_err
(
GHES_PFX
"Failed to map GSI to IRQ for generic hardware error source: %d
\n
"
,
generic
->
header
.
source_id
);
goto
err
;
}
if
(
request_irq
(
ghes
->
irq
,
ghes_irq_func
,
0
,
"GHES IRQ"
,
ghes
))
{
pr_err
(
GHES_PFX
"Failed to register IRQ for generic hardware error source: %d
\n
"
,
generic
->
header
.
source_id
);
goto
err
;
}
break
;
case
ACPI_HEST_NOTIFY_SCI
:
mutex_lock
(
&
ghes_list_mutex
);
if
(
list_empty
(
&
ghes_sci
))
register_acpi_hed_notifier
(
&
ghes_notifier_sci
);
list_add_rcu
(
&
ghes
->
list
,
&
ghes_sci
);
mutex_unlock
(
&
ghes_list_mutex
);
}
else
{
unsigned
char
*
notify
=
NULL
;
switch
(
generic
->
notify
.
type
)
{
case
ACPI_HEST_NOTIFY_POLLED
:
notify
=
"POLL"
;
break
;
case
ACPI_HEST_NOTIFY_EXTERNAL
:
case
ACPI_HEST_NOTIFY_LOCAL
:
notify
=
"IRQ"
;
break
;
case
ACPI_HEST_NOTIFY_NMI
:
notify
=
"NMI"
;
break
;
}
if
(
notify
)
{
pr_warning
(
GHES_PFX
"Generic hardware error source: %d notified via %s is not supported!
\n
"
,
generic
->
header
.
source_id
,
notify
);
}
else
{
pr_warning
(
FW_WARN
GHES_PFX
"Unknown notification type: %u for generic hardware error source: %d
\n
"
,
generic
->
notify
.
type
,
generic
->
header
.
source_id
);
}
rc
=
-
ENODEV
;
goto
err
;
break
;
case
ACPI_HEST_NOTIFY_NMI
:
mutex_lock
(
&
ghes_list_mutex
);
if
(
list_empty
(
&
ghes_nmi
))
register_die_notifier
(
&
ghes_notifier_nmi
);
list_add_rcu
(
&
ghes
->
list
,
&
ghes_nmi
);
mutex_unlock
(
&
ghes_list_mutex
);
break
;
default:
BUG
();
}
platform_set_drvdata
(
ghes_dev
,
ghes
);
...
...
@@ -379,7 +601,14 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
ghes
=
platform_get_drvdata
(
ghes_dev
);
generic
=
ghes
->
generic
;
ghes
->
flags
|=
GHES_EXITING
;
switch
(
generic
->
notify
.
type
)
{
case
ACPI_HEST_NOTIFY_POLLED
:
del_timer_sync
(
&
ghes
->
timer
);
break
;
case
ACPI_HEST_NOTIFY_EXTERNAL
:
free_irq
(
ghes
->
irq
,
ghes
);
break
;
case
ACPI_HEST_NOTIFY_SCI
:
mutex_lock
(
&
ghes_list_mutex
);
list_del_rcu
(
&
ghes
->
list
);
...
...
@@ -387,12 +616,23 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
unregister_acpi_hed_notifier
(
&
ghes_notifier_sci
);
mutex_unlock
(
&
ghes_list_mutex
);
break
;
case
ACPI_HEST_NOTIFY_NMI
:
mutex_lock
(
&
ghes_list_mutex
);
list_del_rcu
(
&
ghes
->
list
);
if
(
list_empty
(
&
ghes_nmi
))
unregister_die_notifier
(
&
ghes_notifier_nmi
);
mutex_unlock
(
&
ghes_list_mutex
);
/*
* To synchronize with NMI handler, ghes can only be
* freed after NMI handler finishes.
*/
synchronize_rcu
();
break
;
default:
BUG
();
break
;
}
synchronize_rcu
();
ghes_fini
(
ghes
);
kfree
(
ghes
);
...
...
@@ -412,6 +652,8 @@ static struct platform_driver ghes_platform_driver = {
static
int
__init
ghes_init
(
void
)
{
int
rc
;
if
(
acpi_disabled
)
return
-
ENODEV
;
...
...
@@ -420,12 +662,25 @@ static int __init ghes_init(void)
return
-
EINVAL
;
}
return
platform_driver_register
(
&
ghes_platform_driver
);
rc
=
ghes_ioremap_init
();
if
(
rc
)
goto
err
;
rc
=
platform_driver_register
(
&
ghes_platform_driver
);
if
(
rc
)
goto
err_ioremap_exit
;
return
0
;
err_ioremap_exit:
ghes_ioremap_exit
();
err:
return
rc
;
}
static
void
__exit
ghes_exit
(
void
)
{
platform_driver_unregister
(
&
ghes_platform_driver
);
ghes_ioremap_exit
();
}
module_init
(
ghes_init
);
...
...
include/linux/cper.h
View file @
03b6e6e5
...
...
@@ -39,10 +39,12 @@
* Severity difinition for error_severity in struct cper_record_header
* and section_severity in struct cper_section_descriptor
*/
#define CPER_SEV_RECOVERABLE 0x0
#define CPER_SEV_FATAL 0x1
#define CPER_SEV_CORRECTED 0x2
#define CPER_SEV_INFORMATIONAL 0x3
enum
{
CPER_SEV_RECOVERABLE
,
CPER_SEV_FATAL
,
CPER_SEV_CORRECTED
,
CPER_SEV_INFORMATIONAL
,
};
/*
* Validation bits difinition for validation_bits in struct
...
...
@@ -201,6 +203,47 @@
UUID_LE(0x036F84E1, 0x7F37, 0x428c, 0xA7, 0x9E, 0x57, 0x5F, \
0xDF, 0xAA, 0x84, 0xEC)
#define CPER_PROC_VALID_TYPE 0x0001
#define CPER_PROC_VALID_ISA 0x0002
#define CPER_PROC_VALID_ERROR_TYPE 0x0004
#define CPER_PROC_VALID_OPERATION 0x0008
#define CPER_PROC_VALID_FLAGS 0x0010
#define CPER_PROC_VALID_LEVEL 0x0020
#define CPER_PROC_VALID_VERSION 0x0040
#define CPER_PROC_VALID_BRAND_INFO 0x0080
#define CPER_PROC_VALID_ID 0x0100
#define CPER_PROC_VALID_TARGET_ADDRESS 0x0200
#define CPER_PROC_VALID_REQUESTOR_ID 0x0400
#define CPER_PROC_VALID_RESPONDER_ID 0x0800
#define CPER_PROC_VALID_IP 0x1000
#define CPER_MEM_VALID_ERROR_STATUS 0x0001
#define CPER_MEM_VALID_PHYSICAL_ADDRESS 0x0002
#define CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK 0x0004
#define CPER_MEM_VALID_NODE 0x0008
#define CPER_MEM_VALID_CARD 0x0010
#define CPER_MEM_VALID_MODULE 0x0020
#define CPER_MEM_VALID_BANK 0x0040
#define CPER_MEM_VALID_DEVICE 0x0080
#define CPER_MEM_VALID_ROW 0x0100
#define CPER_MEM_VALID_COLUMN 0x0200
#define CPER_MEM_VALID_BIT_POSITION 0x0400
#define CPER_MEM_VALID_REQUESTOR_ID 0x0800
#define CPER_MEM_VALID_RESPONDER_ID 0x1000
#define CPER_MEM_VALID_TARGET_ID 0x2000
#define CPER_MEM_VALID_ERROR_TYPE 0x4000
#define CPER_PCIE_VALID_PORT_TYPE 0x0001
#define CPER_PCIE_VALID_VERSION 0x0002
#define CPER_PCIE_VALID_COMMAND_STATUS 0x0004
#define CPER_PCIE_VALID_DEVICE_ID 0x0008
#define CPER_PCIE_VALID_SERIAL_NUMBER 0x0010
#define CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS 0x0020
#define CPER_PCIE_VALID_CAPABILITY 0x0040
#define CPER_PCIE_VALID_AER_INFO 0x0080
#define CPER_PCIE_SLOT_SHIFT 3
/*
* All tables and structs must be byte-packed to match CPER
* specification, since the tables are provided by the system BIOS
...
...
@@ -306,6 +349,41 @@ struct cper_sec_mem_err {
__u8
error_type
;
};
struct
cper_sec_pcie
{
__u64
validation_bits
;
__u32
port_type
;
struct
{
__u8
minor
;
__u8
major
;
__u8
reserved
[
2
];
}
version
;
__u16
command
;
__u16
status
;
__u32
reserved
;
struct
{
__u16
vendor_id
;
__u16
device_id
;
__u8
class_code
[
3
];
__u8
function
;
__u8
device
;
__u16
segment
;
__u8
bus
;
__u8
secondary_bus
;
__u16
slot
;
__u8
reserved
;
}
device_id
;
struct
{
__u32
lower
;
__u32
upper
;
}
serial_number
;
struct
{
__u16
secondary_status
;
__u16
control
;
}
bridge
;
__u8
capability
[
60
];
__u8
aer_info
[
96
];
};
/* Reset to default packing */
#pragma pack()
...
...
kernel/panic.c
View file @
03b6e6e5
...
...
@@ -34,6 +34,7 @@ static int pause_on_oops_flag;
static
DEFINE_SPINLOCK
(
pause_on_oops_lock
);
int
panic_timeout
;
EXPORT_SYMBOL_GPL
(
panic_timeout
);
ATOMIC_NOTIFIER_HEAD
(
panic_notifier_list
);
...
...
lib/ioremap.c
View file @
03b6e6e5
...
...
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/io.h>
#include <linux/module.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
...
...
@@ -90,3 +91,4 @@ int ioremap_page_range(unsigned long addr,
return
err
;
}
EXPORT_SYMBOL_GPL
(
ioremap_page_range
);
mm/vmalloc.c
View file @
03b6e6e5
...
...
@@ -1175,6 +1175,7 @@ void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
{
vunmap_page_range
(
addr
,
addr
+
size
);
}
EXPORT_SYMBOL_GPL
(
unmap_kernel_range_noflush
);
/**
* unmap_kernel_range - unmap kernel VM area and flush cache and TLB
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment