Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
feb29c51
K
Kernel
项目概览
openeuler
/
Kernel
接近 2 年 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
feb29c51
编写于
8月 14, 2010
作者:
L
Len Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'apei' into release
上级
f2a66185
2ff729d5
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
386 addition
and
95 deletion
+386
-95
arch/x86/kernel/cpu/mcheck/mce-apei.c
arch/x86/kernel/cpu/mcheck/mce-apei.c
+2
-2
drivers/acpi/apei/Kconfig
drivers/acpi/apei/Kconfig
+9
-0
drivers/acpi/apei/Makefile
drivers/acpi/apei/Makefile
+1
-0
drivers/acpi/apei/apei-base.c
drivers/acpi/apei/apei-base.c
+2
-2
drivers/acpi/apei/erst-dbg.c
drivers/acpi/apei/erst-dbg.c
+207
-0
drivers/acpi/apei/ghes.c
drivers/acpi/apei/ghes.c
+91
-81
drivers/acpi/apei/hest.c
drivers/acpi/apei/hest.c
+70
-6
include/linux/cper.h
include/linux/cper.h
+4
-4
未找到文件。
arch/x86/kernel/cpu/mcheck/mce-apei.c
浏览文件 @
feb29c51
...
@@ -80,7 +80,7 @@ int apei_write_mce(struct mce *m)
...
@@ -80,7 +80,7 @@ int apei_write_mce(struct mce *m)
rcd
.
hdr
.
revision
=
CPER_RECORD_REV
;
rcd
.
hdr
.
revision
=
CPER_RECORD_REV
;
rcd
.
hdr
.
signature_end
=
CPER_SIG_END
;
rcd
.
hdr
.
signature_end
=
CPER_SIG_END
;
rcd
.
hdr
.
section_count
=
1
;
rcd
.
hdr
.
section_count
=
1
;
rcd
.
hdr
.
error_severity
=
CPER_SE
R
_FATAL
;
rcd
.
hdr
.
error_severity
=
CPER_SE
V
_FATAL
;
/* timestamp, platform_id, partition_id are all invalid */
/* timestamp, platform_id, partition_id are all invalid */
rcd
.
hdr
.
validation_bits
=
0
;
rcd
.
hdr
.
validation_bits
=
0
;
rcd
.
hdr
.
record_length
=
sizeof
(
rcd
);
rcd
.
hdr
.
record_length
=
sizeof
(
rcd
);
...
@@ -96,7 +96,7 @@ int apei_write_mce(struct mce *m)
...
@@ -96,7 +96,7 @@ int apei_write_mce(struct mce *m)
rcd
.
sec_hdr
.
validation_bits
=
0
;
rcd
.
sec_hdr
.
validation_bits
=
0
;
rcd
.
sec_hdr
.
flags
=
CPER_SEC_PRIMARY
;
rcd
.
sec_hdr
.
flags
=
CPER_SEC_PRIMARY
;
rcd
.
sec_hdr
.
section_type
=
CPER_SECTION_TYPE_MCE
;
rcd
.
sec_hdr
.
section_type
=
CPER_SECTION_TYPE_MCE
;
rcd
.
sec_hdr
.
section_severity
=
CPER_SE
R
_FATAL
;
rcd
.
sec_hdr
.
section_severity
=
CPER_SE
V
_FATAL
;
memcpy
(
&
rcd
.
mce
,
m
,
sizeof
(
*
m
));
memcpy
(
&
rcd
.
mce
,
m
,
sizeof
(
*
m
));
...
...
drivers/acpi/apei/Kconfig
浏览文件 @
feb29c51
...
@@ -28,3 +28,12 @@ config ACPI_APEI_EINJ
...
@@ -28,3 +28,12 @@ config ACPI_APEI_EINJ
EINJ provides a hardware error injection mechanism, it is
EINJ provides a hardware error injection mechanism, it is
mainly used for debugging and testing the other parts of
mainly used for debugging and testing the other parts of
APEI and some other RAS features.
APEI and some other RAS features.
config ACPI_APEI_ERST_DEBUG
tristate "APEI Error Record Serialization Table (ERST) Debug Support"
depends on ACPI_APEI
help
ERST is a way provided by APEI to save and retrieve hardware
error infomation to and from a persistent store. Enable this
if you want to debugging and testing the ERST kernel support
and firmware implementation.
drivers/acpi/apei/Makefile
浏览文件 @
feb29c51
obj-$(CONFIG_ACPI_APEI)
+=
apei.o
obj-$(CONFIG_ACPI_APEI)
+=
apei.o
obj-$(CONFIG_ACPI_APEI_GHES)
+=
ghes.o
obj-$(CONFIG_ACPI_APEI_GHES)
+=
ghes.o
obj-$(CONFIG_ACPI_APEI_EINJ)
+=
einj.o
obj-$(CONFIG_ACPI_APEI_EINJ)
+=
einj.o
obj-$(CONFIG_ACPI_APEI_ERST_DEBUG)
+=
erst-dbg.o
apei-y
:=
apei-base.o hest.o cper.o erst.o
apei-y
:=
apei-base.o hest.o cper.o erst.o
drivers/acpi/apei/apei-base.c
浏览文件 @
feb29c51
...
@@ -482,14 +482,14 @@ int apei_resources_request(struct apei_resources *resources,
...
@@ -482,14 +482,14 @@ int apei_resources_request(struct apei_resources *resources,
list_for_each_entry
(
res
,
&
resources
->
ioport
,
list
)
{
list_for_each_entry
(
res
,
&
resources
->
ioport
,
list
)
{
if
(
res
==
res_bak
)
if
(
res
==
res_bak
)
break
;
break
;
release_
mem_
region
(
res
->
start
,
res
->
end
-
res
->
start
);
release_region
(
res
->
start
,
res
->
end
-
res
->
start
);
}
}
res_bak
=
NULL
;
res_bak
=
NULL
;
err_unmap_iomem:
err_unmap_iomem:
list_for_each_entry
(
res
,
&
resources
->
iomem
,
list
)
{
list_for_each_entry
(
res
,
&
resources
->
iomem
,
list
)
{
if
(
res
==
res_bak
)
if
(
res
==
res_bak
)
break
;
break
;
release_region
(
res
->
start
,
res
->
end
-
res
->
start
);
release_
mem_
region
(
res
->
start
,
res
->
end
-
res
->
start
);
}
}
return
-
EINVAL
;
return
-
EINVAL
;
}
}
...
...
drivers/acpi/apei/erst-dbg.c
0 → 100644
浏览文件 @
feb29c51
/*
* APEI Error Record Serialization Table debug support
*
* ERST is a way provided by APEI to save and retrieve hardware error
* infomation to and from a persistent store. This file provide the
* debugging/testing support for ERST kernel support and firmware
* implementation.
*
* Copyright 2010 Intel Corp.
* Author: Huang Ying <ying.huang@intel.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <acpi/apei.h>
#include <linux/miscdevice.h>
#include "apei-internal.h"
#define ERST_DBG_PFX "ERST DBG: "
#define ERST_DBG_RECORD_LEN_MAX 4096
static
void
*
erst_dbg_buf
;
static
unsigned
int
erst_dbg_buf_len
;
/* Prevent erst_dbg_read/write from being invoked concurrently */
static
DEFINE_MUTEX
(
erst_dbg_mutex
);
static
int
erst_dbg_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
if
(
erst_disable
)
return
-
ENODEV
;
return
nonseekable_open
(
inode
,
file
);
}
static
long
erst_dbg_ioctl
(
struct
file
*
f
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
rc
;
u64
record_id
;
u32
record_count
;
switch
(
cmd
)
{
case
APEI_ERST_CLEAR_RECORD
:
rc
=
copy_from_user
(
&
record_id
,
(
void
__user
*
)
arg
,
sizeof
(
record_id
));
if
(
rc
)
return
-
EFAULT
;
return
erst_clear
(
record_id
);
case
APEI_ERST_GET_RECORD_COUNT
:
rc
=
erst_get_record_count
();
if
(
rc
<
0
)
return
rc
;
record_count
=
rc
;
rc
=
put_user
(
record_count
,
(
u32
__user
*
)
arg
);
if
(
rc
)
return
rc
;
return
0
;
default:
return
-
ENOTTY
;
}
}
static
ssize_t
erst_dbg_read
(
struct
file
*
filp
,
char
__user
*
ubuf
,
size_t
usize
,
loff_t
*
off
)
{
int
rc
;
ssize_t
len
=
0
;
u64
id
;
if
(
*
off
!=
0
)
return
-
EINVAL
;
if
(
mutex_lock_interruptible
(
&
erst_dbg_mutex
)
!=
0
)
return
-
EINTR
;
retry_next:
rc
=
erst_get_next_record_id
(
&
id
);
if
(
rc
)
goto
out
;
/* no more record */
if
(
id
==
APEI_ERST_INVALID_RECORD_ID
)
goto
out
;
retry:
rc
=
len
=
erst_read
(
id
,
erst_dbg_buf
,
erst_dbg_buf_len
);
/* The record may be cleared by others, try read next record */
if
(
rc
==
-
ENOENT
)
goto
retry_next
;
if
(
rc
<
0
)
goto
out
;
if
(
len
>
ERST_DBG_RECORD_LEN_MAX
)
{
pr_warning
(
ERST_DBG_PFX
"Record (ID: 0x%llx) length is too long: %zd
\n
"
,
id
,
len
);
rc
=
-
EIO
;
goto
out
;
}
if
(
len
>
erst_dbg_buf_len
)
{
kfree
(
erst_dbg_buf
);
rc
=
-
ENOMEM
;
erst_dbg_buf
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
erst_dbg_buf
)
goto
out
;
erst_dbg_buf_len
=
len
;
goto
retry
;
}
rc
=
-
EINVAL
;
if
(
len
>
usize
)
goto
out
;
rc
=
-
EFAULT
;
if
(
copy_to_user
(
ubuf
,
erst_dbg_buf
,
len
))
goto
out
;
rc
=
0
;
out:
mutex_unlock
(
&
erst_dbg_mutex
);
return
rc
?
rc
:
len
;
}
static
ssize_t
erst_dbg_write
(
struct
file
*
filp
,
const
char
__user
*
ubuf
,
size_t
usize
,
loff_t
*
off
)
{
int
rc
;
struct
cper_record_header
*
rcd
;
if
(
!
capable
(
CAP_SYS_ADMIN
))
return
-
EPERM
;
if
(
usize
>
ERST_DBG_RECORD_LEN_MAX
)
{
pr_err
(
ERST_DBG_PFX
"Too long record to be written
\n
"
);
return
-
EINVAL
;
}
if
(
mutex_lock_interruptible
(
&
erst_dbg_mutex
))
return
-
EINTR
;
if
(
usize
>
erst_dbg_buf_len
)
{
kfree
(
erst_dbg_buf
);
rc
=
-
ENOMEM
;
erst_dbg_buf
=
kmalloc
(
usize
,
GFP_KERNEL
);
if
(
!
erst_dbg_buf
)
goto
out
;
erst_dbg_buf_len
=
usize
;
}
rc
=
copy_from_user
(
erst_dbg_buf
,
ubuf
,
usize
);
if
(
rc
)
{
rc
=
-
EFAULT
;
goto
out
;
}
rcd
=
erst_dbg_buf
;
rc
=
-
EINVAL
;
if
(
rcd
->
record_length
!=
usize
)
goto
out
;
rc
=
erst_write
(
erst_dbg_buf
);
out:
mutex_unlock
(
&
erst_dbg_mutex
);
return
rc
<
0
?
rc
:
usize
;
}
static
const
struct
file_operations
erst_dbg_ops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
erst_dbg_open
,
.
read
=
erst_dbg_read
,
.
write
=
erst_dbg_write
,
.
unlocked_ioctl
=
erst_dbg_ioctl
,
};
static
struct
miscdevice
erst_dbg_dev
=
{
.
minor
=
MISC_DYNAMIC_MINOR
,
.
name
=
"erst_dbg"
,
.
fops
=
&
erst_dbg_ops
,
};
static
__init
int
erst_dbg_init
(
void
)
{
return
misc_register
(
&
erst_dbg_dev
);
}
static
__exit
void
erst_dbg_exit
(
void
)
{
misc_deregister
(
&
erst_dbg_dev
);
kfree
(
erst_dbg_buf
);
}
module_init
(
erst_dbg_init
);
module_exit
(
erst_dbg_exit
);
MODULE_AUTHOR
(
"Huang Ying"
);
MODULE_DESCRIPTION
(
"APEI Error Record Serialization Table debug support"
);
MODULE_LICENSE
(
"GPL"
);
drivers/acpi/apei/ghes.c
浏览文件 @
feb29c51
...
@@ -41,6 +41,8 @@
...
@@ -41,6 +41,8 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/cper.h>
#include <linux/cper.h>
#include <linux/kdebug.h>
#include <linux/kdebug.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <acpi/apei.h>
#include <acpi/apei.h>
#include <acpi/atomicio.h>
#include <acpi/atomicio.h>
#include <acpi/hed.h>
#include <acpi/hed.h>
...
@@ -87,6 +89,7 @@ struct ghes {
...
@@ -87,6 +89,7 @@ struct ghes {
* used for that.
* used for that.
*/
*/
static
LIST_HEAD
(
ghes_sci
);
static
LIST_HEAD
(
ghes_sci
);
static
DEFINE_MUTEX
(
ghes_list_mutex
);
static
struct
ghes
*
ghes_new
(
struct
acpi_hest_generic
*
generic
)
static
struct
ghes
*
ghes_new
(
struct
acpi_hest_generic
*
generic
)
{
{
...
@@ -132,26 +135,26 @@ static void ghes_fini(struct ghes *ghes)
...
@@ -132,26 +135,26 @@ static void ghes_fini(struct ghes *ghes)
}
}
enum
{
enum
{
GHES_SE
R
_NO
=
0x0
,
GHES_SE
V
_NO
=
0x0
,
GHES_SE
R
_CORRECTED
=
0x1
,
GHES_SE
V
_CORRECTED
=
0x1
,
GHES_SE
R
_RECOVERABLE
=
0x2
,
GHES_SE
V
_RECOVERABLE
=
0x2
,
GHES_SE
R
_PANIC
=
0x3
,
GHES_SE
V
_PANIC
=
0x3
,
};
};
static
inline
int
ghes_severity
(
int
severity
)
static
inline
int
ghes_severity
(
int
severity
)
{
{
switch
(
severity
)
{
switch
(
severity
)
{
case
CPER_SE
R
_INFORMATIONAL
:
case
CPER_SE
V
_INFORMATIONAL
:
return
GHES_SE
R
_NO
;
return
GHES_SE
V
_NO
;
case
CPER_SE
R
_CORRECTED
:
case
CPER_SE
V
_CORRECTED
:
return
GHES_SE
R
_CORRECTED
;
return
GHES_SE
V
_CORRECTED
;
case
CPER_SE
R
_RECOVERABLE
:
case
CPER_SE
V
_RECOVERABLE
:
return
GHES_SE
R
_RECOVERABLE
;
return
GHES_SE
V
_RECOVERABLE
;
case
CPER_SE
R
_FATAL
:
case
CPER_SE
V
_FATAL
:
return
GHES_SE
R
_PANIC
;
return
GHES_SE
V
_PANIC
;
default:
default:
/* Unkown, go panic */
/* Unkown, go panic */
return
GHES_SE
R
_PANIC
;
return
GHES_SE
V
_PANIC
;
}
}
}
}
...
@@ -237,16 +240,16 @@ static void ghes_clear_estatus(struct ghes *ghes)
...
@@ -237,16 +240,16 @@ static void ghes_clear_estatus(struct ghes *ghes)
static
void
ghes_do_proc
(
struct
ghes
*
ghes
)
static
void
ghes_do_proc
(
struct
ghes
*
ghes
)
{
{
int
se
r
,
processed
=
0
;
int
se
v
,
processed
=
0
;
struct
acpi_hest_generic_data
*
gdata
;
struct
acpi_hest_generic_data
*
gdata
;
se
r
=
ghes_severity
(
ghes
->
estatus
->
error_severity
);
se
v
=
ghes_severity
(
ghes
->
estatus
->
error_severity
);
apei_estatus_for_each_section
(
ghes
->
estatus
,
gdata
)
{
apei_estatus_for_each_section
(
ghes
->
estatus
,
gdata
)
{
#ifdef CONFIG_X86_MCE
#ifdef CONFIG_X86_MCE
if
(
!
uuid_le_cmp
(
*
(
uuid_le
*
)
gdata
->
section_type
,
if
(
!
uuid_le_cmp
(
*
(
uuid_le
*
)
gdata
->
section_type
,
CPER_SEC_PLATFORM_MEM
))
{
CPER_SEC_PLATFORM_MEM
))
{
apei_mce_report_mem_error
(
apei_mce_report_mem_error
(
se
r
==
GHES_SER
_CORRECTED
,
se
v
==
GHES_SEV
_CORRECTED
,
(
struct
cper_sec_mem_err
*
)(
gdata
+
1
));
(
struct
cper_sec_mem_err
*
)(
gdata
+
1
));
processed
=
1
;
processed
=
1
;
}
}
...
@@ -293,18 +296,15 @@ static struct notifier_block ghes_notifier_sci = {
...
@@ -293,18 +296,15 @@ static struct notifier_block ghes_notifier_sci = {
.
notifier_call
=
ghes_notify_sci
,
.
notifier_call
=
ghes_notify_sci
,
};
};
static
int
hest_ghes_parse
(
struct
acpi_hest_header
*
hest_hdr
,
void
*
data
)
static
int
__devinit
ghes_probe
(
struct
platform_device
*
ghes_dev
)
{
{
struct
acpi_hest_generic
*
generic
;
struct
acpi_hest_generic
*
generic
;
struct
ghes
*
ghes
=
NULL
;
struct
ghes
*
ghes
=
NULL
;
int
rc
=
0
;
int
rc
=
-
EINVAL
;
if
(
hest_hdr
->
type
!=
ACPI_HEST_TYPE_GENERIC_ERROR
)
generic
=
ghes_dev
->
dev
.
platform_data
;
return
0
;
generic
=
(
struct
acpi_hest_generic
*
)
hest_hdr
;
if
(
!
generic
->
enabled
)
if
(
!
generic
->
enabled
)
return
0
;
return
-
ENODEV
;
if
(
generic
->
error_block_length
<
if
(
generic
->
error_block_length
<
sizeof
(
struct
acpi_hest_generic_status
))
{
sizeof
(
struct
acpi_hest_generic_status
))
{
...
@@ -327,62 +327,91 @@ static int hest_ghes_parse(struct acpi_hest_header *hest_hdr, void *data)
...
@@ -327,62 +327,91 @@ static int hest_ghes_parse(struct acpi_hest_header *hest_hdr, void *data)
ghes
=
NULL
;
ghes
=
NULL
;
goto
err
;
goto
err
;
}
}
switch
(
generic
->
notify
.
type
)
{
if
(
generic
->
notify
.
type
==
ACPI_HEST_NOTIFY_SCI
)
{
case
ACPI_HEST_NOTIFY_POLLED
:
mutex_lock
(
&
ghes_list_mutex
);
pr_warning
(
GHES_PFX
"Generic hardware error source: %d notified via POLL is not supported!
\n
"
,
generic
->
header
.
source_id
);
break
;
case
ACPI_HEST_NOTIFY_EXTERNAL
:
case
ACPI_HEST_NOTIFY_LOCAL
:
pr_warning
(
GHES_PFX
"Generic hardware error source: %d notified via IRQ is not supported!
\n
"
,
generic
->
header
.
source_id
);
break
;
case
ACPI_HEST_NOTIFY_SCI
:
if
(
list_empty
(
&
ghes_sci
))
if
(
list_empty
(
&
ghes_sci
))
register_acpi_hed_notifier
(
&
ghes_notifier_sci
);
register_acpi_hed_notifier
(
&
ghes_notifier_sci
);
list_add_rcu
(
&
ghes
->
list
,
&
ghes_sci
);
list_add_rcu
(
&
ghes
->
list
,
&
ghes_sci
);
break
;
mutex_unlock
(
&
ghes_list_mutex
);
case
ACPI_HEST_NOTIFY_NMI
:
}
else
{
pr_warning
(
GHES_PFX
unsigned
char
*
notify
=
NULL
;
"Generic hardware error source: %d notified via NMI is not supported!
\n
"
,
generic
->
header
.
source_id
);
switch
(
generic
->
notify
.
type
)
{
break
;
case
ACPI_HEST_NOTIFY_POLLED
:
default:
notify
=
"POLL"
;
pr_warning
(
FW_WARN
GHES_PFX
break
;
"Unknown notification type: %u for generic hardware error source: %d
\n
"
,
case
ACPI_HEST_NOTIFY_EXTERNAL
:
generic
->
notify
.
type
,
generic
->
header
.
source_id
);
case
ACPI_HEST_NOTIFY_LOCAL
:
break
;
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
;
}
}
platform_set_drvdata
(
ghes_dev
,
ghes
);
return
0
;
return
0
;
err:
err:
if
(
ghes
)
if
(
ghes
)
{
ghes_fini
(
ghes
);
ghes_fini
(
ghes
);
kfree
(
ghes
);
}
return
rc
;
return
rc
;
}
}
static
void
ghes_cleanup
(
void
)
static
int
__devexit
ghes_remove
(
struct
platform_device
*
ghes_dev
)
{
{
struct
ghes
*
ghes
,
*
nghes
;
struct
ghes
*
ghes
;
struct
acpi_hest_generic
*
generic
;
if
(
!
list_empty
(
&
ghes_sci
))
ghes
=
platform_get_drvdata
(
ghes_dev
);
unregister_acpi_hed_notifier
(
&
ghes_notifier_sci
);
generic
=
ghes
->
generic
;
switch
(
generic
->
notify
.
type
)
{
case
ACPI_HEST_NOTIFY_SCI
:
mutex_lock
(
&
ghes_list_mutex
);
list_del_rcu
(
&
ghes
->
list
);
if
(
list_empty
(
&
ghes_sci
))
unregister_acpi_hed_notifier
(
&
ghes_notifier_sci
);
mutex_unlock
(
&
ghes_list_mutex
);
break
;
default:
BUG
();
break
;
}
synchronize_rcu
();
synchronize_rcu
();
ghes_fini
(
ghes
);
kfree
(
ghes
);
list_for_each_entry_safe
(
ghes
,
nghes
,
&
ghes_sci
,
list
)
{
platform_set_drvdata
(
ghes_dev
,
NULL
);
list_del
(
&
ghes
->
list
);
ghes_fini
(
ghes
);
return
0
;
kfree
(
ghes
);
}
}
}
static
struct
platform_driver
ghes_platform_driver
=
{
.
driver
=
{
.
name
=
"GHES"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
ghes_probe
,
.
remove
=
ghes_remove
,
};
static
int
__init
ghes_init
(
void
)
static
int
__init
ghes_init
(
void
)
{
{
int
rc
;
if
(
acpi_disabled
)
if
(
acpi_disabled
)
return
-
ENODEV
;
return
-
ENODEV
;
...
@@ -391,32 +420,12 @@ static int __init ghes_init(void)
...
@@ -391,32 +420,12 @@ static int __init ghes_init(void)
return
-
EINVAL
;
return
-
EINVAL
;
}
}
rc
=
apei_hest_parse
(
hest_ghes_parse
,
NULL
);
return
platform_driver_register
(
&
ghes_platform_driver
);
if
(
rc
)
{
pr_err
(
GHES_PFX
"Error during parsing HEST generic hardware error sources.
\n
"
);
goto
err_cleanup
;
}
if
(
list_empty
(
&
ghes_sci
))
{
pr_info
(
GHES_PFX
"No functional generic hardware error sources.
\n
"
);
rc
=
-
ENODEV
;
goto
err_cleanup
;
}
pr_info
(
GHES_PFX
"Generic Hardware Error Source support is initialized.
\n
"
);
return
0
;
err_cleanup:
ghes_cleanup
();
return
rc
;
}
}
static
void
__exit
ghes_exit
(
void
)
static
void
__exit
ghes_exit
(
void
)
{
{
ghes_cleanup
(
);
platform_driver_unregister
(
&
ghes_platform_driver
);
}
}
module_init
(
ghes_init
);
module_init
(
ghes_init
);
...
@@ -425,3 +434,4 @@ module_exit(ghes_exit);
...
@@ -425,3 +434,4 @@ module_exit(ghes_exit);
MODULE_AUTHOR
(
"Huang Ying"
);
MODULE_AUTHOR
(
"Huang Ying"
);
MODULE_DESCRIPTION
(
"APEI Generic Hardware Error Source support"
);
MODULE_DESCRIPTION
(
"APEI Generic Hardware Error Source support"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:GHES"
);
drivers/acpi/apei/hest.c
浏览文件 @
feb29c51
...
@@ -34,6 +34,7 @@
...
@@ -34,6 +34,7 @@
#include <linux/kdebug.h>
#include <linux/kdebug.h>
#include <linux/highmem.h>
#include <linux/highmem.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <acpi/apei.h>
#include <acpi/apei.h>
#include "apei-internal.h"
#include "apei-internal.h"
...
@@ -47,11 +48,6 @@ EXPORT_SYMBOL_GPL(hest_disable);
...
@@ -47,11 +48,6 @@ EXPORT_SYMBOL_GPL(hest_disable);
static
struct
acpi_table_hest
*
hest_tab
;
static
struct
acpi_table_hest
*
hest_tab
;
static
int
hest_void_parse
(
struct
acpi_hest_header
*
hest_hdr
,
void
*
data
)
{
return
0
;
}
static
int
hest_esrc_len_tab
[
ACPI_HEST_TYPE_RESERVED
]
=
{
static
int
hest_esrc_len_tab
[
ACPI_HEST_TYPE_RESERVED
]
=
{
[
ACPI_HEST_TYPE_IA32_CHECK
]
=
-
1
,
/* need further calculation */
[
ACPI_HEST_TYPE_IA32_CHECK
]
=
-
1
,
/* need further calculation */
[
ACPI_HEST_TYPE_IA32_CORRECTED_CHECK
]
=
-
1
,
[
ACPI_HEST_TYPE_IA32_CORRECTED_CHECK
]
=
-
1
,
...
@@ -125,6 +121,69 @@ int apei_hest_parse(apei_hest_func_t func, void *data)
...
@@ -125,6 +121,69 @@ int apei_hest_parse(apei_hest_func_t func, void *data)
}
}
EXPORT_SYMBOL_GPL
(
apei_hest_parse
);
EXPORT_SYMBOL_GPL
(
apei_hest_parse
);
struct
ghes_arr
{
struct
platform_device
**
ghes_devs
;
unsigned
int
count
;
};
static
int
hest_parse_ghes_count
(
struct
acpi_hest_header
*
hest_hdr
,
void
*
data
)
{
int
*
count
=
data
;
if
(
hest_hdr
->
type
==
ACPI_HEST_TYPE_GENERIC_ERROR
)
(
*
count
)
++
;
return
0
;
}
static
int
hest_parse_ghes
(
struct
acpi_hest_header
*
hest_hdr
,
void
*
data
)
{
struct
acpi_hest_generic
*
generic
;
struct
platform_device
*
ghes_dev
;
struct
ghes_arr
*
ghes_arr
=
data
;
int
rc
;
if
(
hest_hdr
->
type
!=
ACPI_HEST_TYPE_GENERIC_ERROR
)
return
0
;
generic
=
(
struct
acpi_hest_generic
*
)
hest_hdr
;
if
(
!
generic
->
enabled
)
return
0
;
ghes_dev
=
platform_device_alloc
(
"GHES"
,
hest_hdr
->
source_id
);
if
(
!
ghes_dev
)
return
-
ENOMEM
;
ghes_dev
->
dev
.
platform_data
=
generic
;
rc
=
platform_device_add
(
ghes_dev
);
if
(
rc
)
goto
err
;
ghes_arr
->
ghes_devs
[
ghes_arr
->
count
++
]
=
ghes_dev
;
return
0
;
err:
platform_device_put
(
ghes_dev
);
return
rc
;
}
static
int
hest_ghes_dev_register
(
unsigned
int
ghes_count
)
{
int
rc
,
i
;
struct
ghes_arr
ghes_arr
;
ghes_arr
.
count
=
0
;
ghes_arr
.
ghes_devs
=
kmalloc
(
sizeof
(
void
*
)
*
ghes_count
,
GFP_KERNEL
);
if
(
!
ghes_arr
.
ghes_devs
)
return
-
ENOMEM
;
rc
=
apei_hest_parse
(
hest_parse_ghes
,
&
ghes_arr
);
if
(
rc
)
goto
err
;
out:
kfree
(
ghes_arr
.
ghes_devs
);
return
rc
;
err:
for
(
i
=
0
;
i
<
ghes_arr
.
count
;
i
++
)
platform_device_unregister
(
ghes_arr
.
ghes_devs
[
i
]);
goto
out
;
}
static
int
__init
setup_hest_disable
(
char
*
str
)
static
int
__init
setup_hest_disable
(
char
*
str
)
{
{
hest_disable
=
1
;
hest_disable
=
1
;
...
@@ -137,6 +196,7 @@ static int __init hest_init(void)
...
@@ -137,6 +196,7 @@ static int __init hest_init(void)
{
{
acpi_status
status
;
acpi_status
status
;
int
rc
=
-
ENODEV
;
int
rc
=
-
ENODEV
;
unsigned
int
ghes_count
=
0
;
if
(
acpi_disabled
)
if
(
acpi_disabled
)
goto
err
;
goto
err
;
...
@@ -158,7 +218,11 @@ static int __init hest_init(void)
...
@@ -158,7 +218,11 @@ static int __init hest_init(void)
goto
err
;
goto
err
;
}
}
rc
=
apei_hest_parse
(
hest_void_parse
,
NULL
);
rc
=
apei_hest_parse
(
hest_parse_ghes_count
,
&
ghes_count
);
if
(
rc
)
goto
err
;
rc
=
hest_ghes_dev_register
(
ghes_count
);
if
(
rc
)
if
(
rc
)
goto
err
;
goto
err
;
...
...
include/linux/cper.h
浏览文件 @
feb29c51
...
@@ -39,10 +39,10 @@
...
@@ -39,10 +39,10 @@
* Severity difinition for error_severity in struct cper_record_header
* Severity difinition for error_severity in struct cper_record_header
* and section_severity in struct cper_section_descriptor
* and section_severity in struct cper_section_descriptor
*/
*/
#define CPER_SE
R
_RECOVERABLE 0x0
#define CPER_SE
V
_RECOVERABLE 0x0
#define CPER_SE
R
_FATAL 0x1
#define CPER_SE
V
_FATAL 0x1
#define CPER_SE
R
_CORRECTED 0x2
#define CPER_SE
V
_CORRECTED 0x2
#define CPER_SE
R
_INFORMATIONAL 0x3
#define CPER_SE
V
_INFORMATIONAL 0x3
/*
/*
* Validation bits difinition for validation_bits in struct
* Validation bits difinition for validation_bits in struct
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录