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
037d76f4
Commit
037d76f4
authored
Jan 18, 2012
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'apei' into release
parents
5d1f8657
4134b8c8
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
321 additions
and
55 deletions
+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
No files found.
arch/x86/kernel/e820.c
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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*/
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