Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
gsplhtlxg
clone-Linux
提交
037d76f4
C
clone-Linux
项目概览
gsplhtlxg
/
clone-Linux
通知
2
Star
0
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
clone-Linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
037d76f4
编写于
1月 18, 2012
作者:
L
Len Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'apei' into release
上级
5d1f8657
4134b8c8
变更
11
隐藏空白更改
内联
并排
Showing
11 changed file
with
321 addition
and
55 deletion
+321
-55
arch/x86/kernel/e820.c
arch/x86/kernel/e820.c
+2
-2
drivers/acpi/Makefile
drivers/acpi/Makefile
+2
-1
drivers/acpi/apei/apei-base.c
drivers/acpi/apei/apei-base.c
+43
-5
drivers/acpi/apei/apei-internal.h
drivers/acpi/apei/apei-internal.h
+3
-0
drivers/acpi/apei/einj.c
drivers/acpi/apei/einj.c
+56
-10
drivers/acpi/apei/erst.c
drivers/acpi/apei/erst.c
+2
-3
drivers/acpi/apei/ghes.c
drivers/acpi/apei/ghes.c
+78
-14
drivers/acpi/apei/hest.c
drivers/acpi/apei/hest.c
+2
-3
drivers/acpi/atomicio.c
drivers/acpi/atomicio.c
+67
-10
drivers/acpi/nvs.c
drivers/acpi/nvs.c
+52
-1
include/linux/acpi.h
include/linux/acpi.h
+14
-6
未找到文件。
arch/x86/kernel/e820.c
浏览文件 @
037d76f4
...
...
@@ -714,7 +714,7 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn)
}
#endif
#ifdef CONFIG_
HIBERNATION
#ifdef CONFIG_
ACPI
/**
* Mark ACPI NVS memory region, so that we can save/restore it during
* hibernation and the subsequent resume.
...
...
@@ -727,7 +727,7 @@ static int __init e820_mark_nvs_memory(void)
struct
e820entry
*
ei
=
&
e820
.
map
[
i
];
if
(
ei
->
type
==
E820_NVS
)
suspend
_nvs_register
(
ei
->
addr
,
ei
->
size
);
acpi
_nvs_register
(
ei
->
addr
,
ei
->
size
);
}
return
0
;
...
...
drivers/acpi/Makefile
浏览文件 @
037d76f4
...
...
@@ -20,11 +20,12 @@ obj-y += acpi.o \
# All the builtin files are in the "acpi." module_param namespace.
acpi-y
+=
osl.o utils.o reboot.o
acpi-y
+=
atomicio.o
acpi-y
+=
nvs.o
# sleep related files
acpi-y
+=
wakeup.o
acpi-y
+=
sleep.o
acpi-$(CONFIG_ACPI_SLEEP)
+=
proc.o
nvs.o
acpi-$(CONFIG_ACPI_SLEEP)
+=
proc.o
#
...
...
drivers/acpi/apei/apei-base.c
浏览文件 @
037d76f4
...
...
@@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1,
return
0
;
}
int
apei_resources_add
(
struct
apei_resources
*
resources
,
unsigned
long
start
,
unsigned
long
size
,
bool
iomem
)
{
if
(
iomem
)
return
apei_res_add
(
&
resources
->
iomem
,
start
,
size
);
else
return
apei_res_add
(
&
resources
->
ioport
,
start
,
size
);
}
EXPORT_SYMBOL_GPL
(
apei_resources_add
);
/*
* EINJ has two groups of GARs (EINJ table entry and trigger table
* entry), so common resources are subtracted from the trigger table
...
...
@@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1,
}
EXPORT_SYMBOL_GPL
(
apei_resources_sub
);
static
int
apei_get_nvs_callback
(
__u64
start
,
__u64
size
,
void
*
data
)
{
struct
apei_resources
*
resources
=
data
;
return
apei_res_add
(
&
resources
->
iomem
,
start
,
size
);
}
static
int
apei_get_nvs_resources
(
struct
apei_resources
*
resources
)
{
return
acpi_nvs_for_each_region
(
apei_get_nvs_callback
,
resources
);
}
/*
* IO memory/port re
r
source management mechanism is used to check
* IO memory/port resource management mechanism is used to check
* whether memory/port area used by GARs conflicts with normal memory
* or IO memory/port of devices.
*/
...
...
@@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources,
{
struct
apei_res
*
res
,
*
res_bak
=
NULL
;
struct
resource
*
r
;
struct
apei_resources
nvs_resources
;
int
rc
;
rc
=
apei_resources_sub
(
resources
,
&
apei_resources_all
);
if
(
rc
)
return
rc
;
/*
* Some firmware uses ACPI NVS region, that has been marked as
* busy, so exclude it from APEI resources to avoid false
* conflict.
*/
apei_resources_init
(
&
nvs_resources
);
rc
=
apei_get_nvs_resources
(
&
nvs_resources
);
if
(
rc
)
goto
res_fini
;
rc
=
apei_resources_sub
(
resources
,
&
nvs_resources
);
if
(
rc
)
goto
res_fini
;
rc
=
-
EINVAL
;
list_for_each_entry
(
res
,
&
resources
->
iomem
,
list
)
{
r
=
request_mem_region
(
res
->
start
,
res
->
end
-
res
->
start
,
desc
);
if
(
!
r
)
{
pr_err
(
APEI_PFX
"Can not request
iomem region <%016llx-%016llx> for GARs.
\n
"
,
"Can not request
[mem %#010llx-%#010llx] for %s registers
\n
"
,
(
unsigned
long
long
)
res
->
start
,
(
unsigned
long
long
)
res
->
end
);
(
unsigned
long
long
)
res
->
end
-
1
,
desc
);
res_bak
=
res
;
goto
err_unmap_iomem
;
}
...
...
@@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources,
r
=
request_region
(
res
->
start
,
res
->
end
-
res
->
start
,
desc
);
if
(
!
r
)
{
pr_err
(
APEI_PFX
"Can not request
ioport region <%016llx-%016llx> for GARs.
\n
"
,
"Can not request
[io %#06llx-%#06llx] for %s registers
\n
"
,
(
unsigned
long
long
)
res
->
start
,
(
unsigned
long
long
)
res
->
end
);
(
unsigned
long
long
)
res
->
end
-
1
,
desc
);
res_bak
=
res
;
goto
err_unmap_ioport
;
}
...
...
@@ -500,6 +536,8 @@ int apei_resources_request(struct apei_resources *resources,
break
;
release_mem_region
(
res
->
start
,
res
->
end
-
res
->
start
);
}
res_fini:
apei_resources_fini
(
&
nvs_resources
);
return
rc
;
}
EXPORT_SYMBOL_GPL
(
apei_resources_request
);
...
...
drivers/acpi/apei/apei-internal.h
浏览文件 @
037d76f4
...
...
@@ -95,6 +95,9 @@ static inline void apei_resources_init(struct apei_resources *resources)
}
void
apei_resources_fini
(
struct
apei_resources
*
resources
);
int
apei_resources_add
(
struct
apei_resources
*
resources
,
unsigned
long
start
,
unsigned
long
size
,
bool
iomem
);
int
apei_resources_sub
(
struct
apei_resources
*
resources1
,
struct
apei_resources
*
resources2
);
int
apei_resources_request
(
struct
apei_resources
*
resources
,
...
...
drivers/acpi/apei/einj.c
浏览文件 @
037d76f4
...
...
@@ -194,8 +194,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
return
0
;
}
static
struct
acpi_generic_address
*
einj_get_trigger_parameter_region
(
struct
acpi_einj_trigger
*
trigger_tab
,
u64
param1
,
u64
param2
)
{
int
i
;
struct
acpi_whea_header
*
entry
;
entry
=
(
struct
acpi_whea_header
*
)
((
char
*
)
trigger_tab
+
sizeof
(
struct
acpi_einj_trigger
));
for
(
i
=
0
;
i
<
trigger_tab
->
entry_count
;
i
++
)
{
if
(
entry
->
action
==
ACPI_EINJ_TRIGGER_ERROR
&&
entry
->
instruction
==
ACPI_EINJ_WRITE_REGISTER_VALUE
&&
entry
->
register_region
.
space_id
==
ACPI_ADR_SPACE_SYSTEM_MEMORY
&&
(
entry
->
register_region
.
address
&
param2
)
==
(
param1
&
param2
))
return
&
entry
->
register_region
;
entry
++
;
}
return
NULL
;
}
/* Execute instructions in trigger error action table */
static
int
__einj_error_trigger
(
u64
trigger_paddr
)
static
int
__einj_error_trigger
(
u64
trigger_paddr
,
u32
type
,
u64
param1
,
u64
param2
)
{
struct
acpi_einj_trigger
*
trigger_tab
=
NULL
;
struct
apei_exec_context
trigger_ctx
;
...
...
@@ -204,14 +225,16 @@ static int __einj_error_trigger(u64 trigger_paddr)
struct
resource
*
r
;
u32
table_size
;
int
rc
=
-
EIO
;
struct
acpi_generic_address
*
trigger_param_region
=
NULL
;
r
=
request_mem_region
(
trigger_paddr
,
sizeof
(
*
trigger_tab
),
"APEI EINJ Trigger Table"
);
if
(
!
r
)
{
pr_err
(
EINJ_PFX
"Can not request
iomem region <%016llx-%016llx> for Trigger table.
\n
"
,
"Can not request
[mem %#010llx-%#010llx] for Trigger table
\n
"
,
(
unsigned
long
long
)
trigger_paddr
,
(
unsigned
long
long
)
trigger_paddr
+
sizeof
(
*
trigger_tab
));
(
unsigned
long
long
)
trigger_paddr
+
sizeof
(
*
trigger_tab
)
-
1
);
goto
out
;
}
trigger_tab
=
ioremap_cache
(
trigger_paddr
,
sizeof
(
*
trigger_tab
));
...
...
@@ -232,9 +255,9 @@ static int __einj_error_trigger(u64 trigger_paddr)
"APEI EINJ Trigger Table"
);
if
(
!
r
)
{
pr_err
(
EINJ_PFX
"Can not request
iomem region <%016llx-%016llx> for Trigger Table Entry.
\n
"
,
(
unsigned
long
long
)
trigger_paddr
+
sizeof
(
*
trigger_tab
),
(
unsigned
long
long
)
trigger_paddr
+
table_size
);
"Can not request
[mem %#010llx-%#010llx] for Trigger Table Entry
\n
"
,
(
unsigned
long
long
)
trigger_paddr
+
sizeof
(
*
trigger_tab
),
(
unsigned
long
long
)
trigger_paddr
+
table_size
-
1
);
goto
out_rel_header
;
}
iounmap
(
trigger_tab
);
...
...
@@ -255,6 +278,30 @@ static int __einj_error_trigger(u64 trigger_paddr)
rc
=
apei_resources_sub
(
&
trigger_resources
,
&
einj_resources
);
if
(
rc
)
goto
out_fini
;
/*
* Some firmware will access target address specified in
* param1 to trigger the error when injecting memory error.
* This will cause resource conflict with regular memory. So
* remove it from trigger table resources.
*/
if
(
param_extension
&&
(
type
&
0x0038
)
&&
param2
)
{
struct
apei_resources
addr_resources
;
apei_resources_init
(
&
addr_resources
);
trigger_param_region
=
einj_get_trigger_parameter_region
(
trigger_tab
,
param1
,
param2
);
if
(
trigger_param_region
)
{
rc
=
apei_resources_add
(
&
addr_resources
,
trigger_param_region
->
address
,
trigger_param_region
->
bit_width
/
8
,
true
);
if
(
rc
)
goto
out_fini
;
rc
=
apei_resources_sub
(
&
trigger_resources
,
&
addr_resources
);
}
apei_resources_fini
(
&
addr_resources
);
if
(
rc
)
goto
out_fini
;
}
rc
=
apei_resources_request
(
&
trigger_resources
,
"APEI EINJ Trigger"
);
if
(
rc
)
goto
out_fini
;
...
...
@@ -324,7 +371,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
if
(
rc
)
return
rc
;
trigger_paddr
=
apei_exec_ctx_get_output
(
&
ctx
);
rc
=
__einj_error_trigger
(
trigger_paddr
);
rc
=
__einj_error_trigger
(
trigger_paddr
,
type
,
param1
,
param2
);
if
(
rc
)
return
rc
;
rc
=
apei_exec_run_optional
(
&
ctx
,
ACPI_EINJ_END_OPERATION
);
...
...
@@ -465,10 +512,9 @@ static int __init einj_init(void)
status
=
acpi_get_table
(
ACPI_SIG_EINJ
,
0
,
(
struct
acpi_table_header
**
)
&
einj_tab
);
if
(
status
==
AE_NOT_FOUND
)
{
pr_info
(
EINJ_PFX
"Table is not found!
\n
"
);
if
(
status
==
AE_NOT_FOUND
)
return
-
ENODEV
;
}
else
if
(
ACPI_FAILURE
(
status
))
{
else
if
(
ACPI_FAILURE
(
status
))
{
const
char
*
msg
=
acpi_format_exception
(
status
);
pr_err
(
EINJ_PFX
"Failed to get table, %s
\n
"
,
msg
);
return
-
EINVAL
;
...
...
drivers/acpi/apei/erst.c
浏览文件 @
037d76f4
...
...
@@ -1125,10 +1125,9 @@ static int __init erst_init(void)
status
=
acpi_get_table
(
ACPI_SIG_ERST
,
0
,
(
struct
acpi_table_header
**
)
&
erst_tab
);
if
(
status
==
AE_NOT_FOUND
)
{
pr_info
(
ERST_PFX
"Table is not found!
\n
"
);
if
(
status
==
AE_NOT_FOUND
)
goto
err
;
}
else
if
(
ACPI_FAILURE
(
status
))
{
else
if
(
ACPI_FAILURE
(
status
))
{
const
char
*
msg
=
acpi_format_exception
(
status
);
pr_err
(
ERST_PFX
"Failed to get table, %s
\n
"
,
msg
);
rc
=
-
EINVAL
;
...
...
drivers/acpi/apei/ghes.c
浏览文件 @
037d76f4
...
...
@@ -45,6 +45,8 @@
#include <linux/irq_work.h>
#include <linux/llist.h>
#include <linux/genalloc.h>
#include <linux/pci.h>
#include <linux/aer.h>
#include <acpi/apei.h>
#include <acpi/atomicio.h>
#include <acpi/hed.h>
...
...
@@ -476,6 +478,27 @@ static void ghes_do_proc(const struct acpi_hest_generic_status *estatus)
}
#endif
}
#ifdef CONFIG_ACPI_APEI_PCIEAER
else
if
(
!
uuid_le_cmp
(
*
(
uuid_le
*
)
gdata
->
section_type
,
CPER_SEC_PCIE
))
{
struct
cper_sec_pcie
*
pcie_err
;
pcie_err
=
(
struct
cper_sec_pcie
*
)(
gdata
+
1
);
if
(
sev
==
GHES_SEV_RECOVERABLE
&&
sec_sev
==
GHES_SEV_RECOVERABLE
&&
pcie_err
->
validation_bits
&
CPER_PCIE_VALID_DEVICE_ID
&&
pcie_err
->
validation_bits
&
CPER_PCIE_VALID_AER_INFO
)
{
unsigned
int
devfn
;
int
aer_severity
;
devfn
=
PCI_DEVFN
(
pcie_err
->
device_id
.
device
,
pcie_err
->
device_id
.
function
);
aer_severity
=
cper_severity_to_aer
(
sev
);
aer_recover_queue
(
pcie_err
->
device_id
.
segment
,
pcie_err
->
device_id
.
bus
,
devfn
,
aer_severity
);
}
}
#endif
}
}
...
...
@@ -483,16 +506,22 @@ static void __ghes_print_estatus(const char *pfx,
const
struct
acpi_hest_generic
*
generic
,
const
struct
acpi_hest_generic_status
*
estatus
)
{
static
atomic_t
seqno
;
unsigned
int
curr_seqno
;
char
pfx_seq
[
64
];
if
(
pfx
==
NULL
)
{
if
(
ghes_severity
(
estatus
->
error_severity
)
<=
GHES_SEV_CORRECTED
)
pfx
=
KERN_WARNING
HW_ERR
;
pfx
=
KERN_WARNING
;
else
pfx
=
KERN_ERR
HW_ERR
;
pfx
=
KERN_ERR
;
}
curr_seqno
=
atomic_inc_return
(
&
seqno
);
snprintf
(
pfx_seq
,
sizeof
(
pfx_seq
),
"%s{%u}"
HW_ERR
,
pfx
,
curr_seqno
);
printk
(
"%s""Hardware error from APEI Generic Hardware Error Source: %d
\n
"
,
pfx
,
generic
->
header
.
source_id
);
apei_estatus_print
(
pfx
,
estatus
);
pfx
_seq
,
generic
->
header
.
source_id
);
apei_estatus_print
(
pfx
_seq
,
estatus
);
}
static
int
ghes_print_estatus
(
const
char
*
pfx
,
...
...
@@ -711,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this,
return
ret
;
}
static
struct
llist_node
*
llist_nodes_reverse
(
struct
llist_node
*
llnode
)
{
struct
llist_node
*
next
,
*
tail
=
NULL
;
while
(
llnode
)
{
next
=
llnode
->
next
;
llnode
->
next
=
tail
;
tail
=
llnode
;
llnode
=
next
;
}
return
tail
;
}
static
void
ghes_proc_in_irq
(
struct
irq_work
*
irq_work
)
{
struct
llist_node
*
llnode
,
*
next
,
*
tail
=
NULL
;
struct
llist_node
*
llnode
,
*
next
;
struct
ghes_estatus_node
*
estatus_node
;
struct
acpi_hest_generic
*
generic
;
struct
acpi_hest_generic_status
*
estatus
;
u32
len
,
node_len
;
llnode
=
llist_del_all
(
&
ghes_estatus_llist
);
/*
* Because the time order of estatus in list is reversed,
* revert it back to proper order.
*/
llnode
=
llist_del_all
(
&
ghes_estatus_llist
);
while
(
llnode
)
{
next
=
llnode
->
next
;
llnode
->
next
=
tail
;
tail
=
llnode
;
llnode
=
next
;
}
llnode
=
tail
;
llnode
=
llist_nodes_reverse
(
llnode
);
while
(
llnode
)
{
next
=
llnode
->
next
;
estatus_node
=
llist_entry
(
llnode
,
struct
ghes_estatus_node
,
...
...
@@ -750,6 +787,32 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
}
}
static
void
ghes_print_queued_estatus
(
void
)
{
struct
llist_node
*
llnode
;
struct
ghes_estatus_node
*
estatus_node
;
struct
acpi_hest_generic
*
generic
;
struct
acpi_hest_generic_status
*
estatus
;
u32
len
,
node_len
;
llnode
=
llist_del_all
(
&
ghes_estatus_llist
);
/*
* Because the time order of estatus in list is reversed,
* revert it back to proper order.
*/
llnode
=
llist_nodes_reverse
(
llnode
);
while
(
llnode
)
{
estatus_node
=
llist_entry
(
llnode
,
struct
ghes_estatus_node
,
llnode
);
estatus
=
GHES_ESTATUS_FROM_NODE
(
estatus_node
);
len
=
apei_estatus_len
(
estatus
);
node_len
=
GHES_ESTATUS_NODE_LEN
(
len
);
generic
=
estatus_node
->
generic
;
ghes_print_estatus
(
NULL
,
generic
,
estatus
);
llnode
=
llnode
->
next
;
}
}
static
int
ghes_notify_nmi
(
unsigned
int
cmd
,
struct
pt_regs
*
regs
)
{
struct
ghes
*
ghes
,
*
ghes_global
=
NULL
;
...
...
@@ -775,7 +838,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
if
(
sev_global
>=
GHES_SEV_PANIC
)
{
oops_begin
();
__ghes_print_estatus
(
KERN_EMERG
HW_ERR
,
ghes_global
->
generic
,
ghes_print_queued_estatus
();
__ghes_print_estatus
(
KERN_EMERG
,
ghes_global
->
generic
,
ghes_global
->
estatus
);
/* reboot to log the error! */
if
(
panic_timeout
==
0
)
...
...
drivers/acpi/apei/hest.c
浏览文件 @
037d76f4
...
...
@@ -221,10 +221,9 @@ void __init acpi_hest_init(void)
status
=
acpi_get_table
(
ACPI_SIG_HEST
,
0
,
(
struct
acpi_table_header
**
)
&
hest_tab
);
if
(
status
==
AE_NOT_FOUND
)
{
pr_info
(
HEST_PFX
"Table not found.
\n
"
);
if
(
status
==
AE_NOT_FOUND
)
goto
err
;
}
else
if
(
ACPI_FAILURE
(
status
))
{
else
if
(
ACPI_FAILURE
(
status
))
{
const
char
*
msg
=
acpi_format_exception
(
status
);
pr_err
(
HEST_PFX
"Failed to get table, %s
\n
"
,
msg
);
rc
=
-
EINVAL
;
...
...
drivers/acpi/atomicio.c
浏览文件 @
037d76f4
...
...
@@ -32,6 +32,8 @@
#include <linux/rculist.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <acpi/atomicio.h>
#define ACPI_PFX "ACPI: "
...
...
@@ -97,6 +99,37 @@ static void __iomem *__acpi_try_ioremap(phys_addr_t paddr,
return
NULL
;
}
#ifndef CONFIG_IA64
#define should_use_kmap(pfn) page_is_ram(pfn)
#else
/* ioremap will take care of cache attributes */
#define should_use_kmap(pfn) 0
#endif
static
void
__iomem
*
acpi_map
(
phys_addr_t
pg_off
,
unsigned
long
pg_sz
)
{
unsigned
long
pfn
;
pfn
=
pg_off
>>
PAGE_SHIFT
;
if
(
should_use_kmap
(
pfn
))
{
if
(
pg_sz
>
PAGE_SIZE
)
return
NULL
;
return
(
void
__iomem
__force
*
)
kmap
(
pfn_to_page
(
pfn
));
}
else
return
ioremap
(
pg_off
,
pg_sz
);
}
static
void
acpi_unmap
(
phys_addr_t
pg_off
,
void
__iomem
*
vaddr
)
{
unsigned
long
pfn
;
pfn
=
pg_off
>>
PAGE_SHIFT
;
if
(
page_is_ram
(
pfn
))
kunmap
(
pfn_to_page
(
pfn
));
else
iounmap
(
vaddr
);
}
/*
* Used to pre-map the specified IO memory area. First try to find
* whether the area is already pre-mapped, if it is, increase the
...
...
@@ -119,7 +152,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
pg_off
=
paddr
&
PAGE_MASK
;
pg_sz
=
((
paddr
+
size
+
PAGE_SIZE
-
1
)
&
PAGE_MASK
)
-
pg_off
;
vaddr
=
iore
map
(
pg_off
,
pg_sz
);
vaddr
=
acpi_
map
(
pg_off
,
pg_sz
);
if
(
!
vaddr
)
return
NULL
;
map
=
kmalloc
(
sizeof
(
*
map
),
GFP_KERNEL
);
...
...
@@ -135,7 +168,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
vaddr
=
__acpi_try_ioremap
(
paddr
,
size
);
if
(
vaddr
)
{
spin_unlock_irqrestore
(
&
acpi_iomaps_lock
,
flags
);
iounmap
(
map
->
vaddr
);
acpi_unmap
(
pg_off
,
map
->
vaddr
);
kfree
(
map
);
return
vaddr
;
}
...
...
@@ -144,7 +177,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
return
map
->
vaddr
+
(
paddr
-
map
->
paddr
);
err_unmap:
iounmap
(
vaddr
);
acpi_unmap
(
pg_off
,
vaddr
);
return
NULL
;
}
...
...
@@ -177,7 +210,7 @@ static void acpi_post_unmap(phys_addr_t paddr, unsigned long size)
return
;
synchronize_rcu
();
iounmap
(
map
->
vaddr
);
acpi_unmap
(
map
->
paddr
,
map
->
vaddr
);
kfree
(
map
);
}
...
...
@@ -260,6 +293,21 @@ int acpi_post_unmap_gar(struct acpi_generic_address *reg)
}
EXPORT_SYMBOL_GPL
(
acpi_post_unmap_gar
);
#ifdef readq
static
inline
u64
read64
(
const
volatile
void
__iomem
*
addr
)
{
return
readq
(
addr
);
}
#else
static
inline
u64
read64
(
const
volatile
void
__iomem
*
addr
)
{
u64
l
,
h
;
l
=
readl
(
addr
);
h
=
readl
(
addr
+
4
);
return
l
|
(
h
<<
32
);
}
#endif
/*
* Can be used in atomic (including NMI) or process context. RCU read
* lock can only be released after the IO memory area accessing.
...
...
@@ -280,11 +328,9 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
case
32
:
*
val
=
readl
(
addr
);
break
;
#ifdef readq
case
64
:
*
val
=
read
q
(
addr
);
*
val
=
read
64
(
addr
);
break
;
#endif
default:
return
-
EINVAL
;
}
...
...
@@ -293,6 +339,19 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
return
0
;
}
#ifdef writeq
static
inline
void
write64
(
u64
val
,
volatile
void
__iomem
*
addr
)
{
writeq
(
val
,
addr
);
}
#else
static
inline
void
write64
(
u64
val
,
volatile
void
__iomem
*
addr
)
{
writel
(
val
,
addr
);
writel
(
val
>>
32
,
addr
+
4
);
}
#endif
static
int
acpi_atomic_write_mem
(
u64
paddr
,
u64
val
,
u32
width
)
{
void
__iomem
*
addr
;
...
...
@@ -309,11 +368,9 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
case
32
:
writel
(
val
,
addr
);
break
;
#ifdef writeq
case
64
:
write
q
(
val
,
addr
);
write
64
(
val
,
addr
);
break
;
#endif
default:
return
-
EINVAL
;
}
...
...
drivers/acpi/nvs.c
浏览文件 @
037d76f4
...
...
@@ -15,6 +15,56 @@
#include <linux/acpi_io.h>
#include <acpi/acpiosxf.h>
/* ACPI NVS regions, APEI may use it */
struct
nvs_region
{
__u64
phys_start
;
__u64
size
;
struct
list_head
node
;
};
static
LIST_HEAD
(
nvs_region_list
);
#ifdef CONFIG_ACPI_SLEEP
static
int
suspend_nvs_register
(
unsigned
long
start
,
unsigned
long
size
);
#else
static
inline
int
suspend_nvs_register
(
unsigned
long
a
,
unsigned
long
b
)
{
return
0
;
}
#endif
int
acpi_nvs_register
(
__u64
start
,
__u64
size
)
{
struct
nvs_region
*
region
;
region
=
kmalloc
(
sizeof
(
*
region
),
GFP_KERNEL
);
if
(
!
region
)
return
-
ENOMEM
;
region
->
phys_start
=
start
;
region
->
size
=
size
;
list_add_tail
(
&
region
->
node
,
&
nvs_region_list
);
return
suspend_nvs_register
(
start
,
size
);
}
int
acpi_nvs_for_each_region
(
int
(
*
func
)(
__u64
start
,
__u64
size
,
void
*
data
),
void
*
data
)
{
int
rc
;
struct
nvs_region
*
region
;
list_for_each_entry
(
region
,
&
nvs_region_list
,
node
)
{
rc
=
func
(
region
->
phys_start
,
region
->
size
,
data
);
if
(
rc
)
return
rc
;
}
return
0
;
}
#ifdef CONFIG_ACPI_SLEEP
/*
* Platforms, like ACPI, may want us to save some memory used by them during
* suspend and to restore the contents of this memory during the subsequent
...
...
@@ -41,7 +91,7 @@ static LIST_HEAD(nvs_list);
* things so that the data from page-aligned addresses in this region will
* be copied into separate RAM pages.
*/
int
suspend_nvs_register
(
unsigned
long
start
,
unsigned
long
size
)
static
int
suspend_nvs_register
(
unsigned
long
start
,
unsigned
long
size
)
{
struct
nvs_page
*
entry
,
*
next
;
...
...
@@ -159,3 +209,4 @@ void suspend_nvs_restore(void)
if
(
entry
->
data
)
memcpy
(
entry
->
kaddr
,
entry
->
data
,
entry
->
size
);
}
#endif
include/linux/acpi.h
浏览文件 @
037d76f4
...
...
@@ -306,6 +306,11 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
u32
*
mask
,
u32
req
);
extern
void
acpi_early_init
(
void
);
extern
int
acpi_nvs_register
(
__u64
start
,
__u64
size
);
extern
int
acpi_nvs_for_each_region
(
int
(
*
func
)(
__u64
,
__u64
,
void
*
),
void
*
data
);
#else
/* !CONFIG_ACPI */
#define acpi_disabled 1
...
...
@@ -348,15 +353,18 @@ static inline int acpi_table_parse(char *id,
{
return
-
1
;
}
#endif
/* !CONFIG_ACPI */
#ifdef CONFIG_ACPI_SLEEP
int
suspend_nvs_register
(
unsigned
long
start
,
unsigned
long
size
);
#else
static
inline
int
suspend_nvs_register
(
unsigned
long
a
,
unsigned
long
b
)
static
inline
int
acpi_nvs_register
(
__u64
start
,
__u64
size
)
{
return
0
;
}
#endif
static
inline
int
acpi_nvs_for_each_region
(
int
(
*
func
)(
__u64
,
__u64
,
void
*
),
void
*
data
)
{
return
0
;
}
#endif
/* !CONFIG_ACPI */
#endif
/*_LINUX_ACPI_H*/
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录