Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
f4b98415
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
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看板
提交
f4b98415
编写于
12月 09, 2010
作者:
B
Benjamin Herrenschmidt
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'nvram' into next
上级
46f52210
6024ede9
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
381 addition
and
363 deletion
+381
-363
arch/powerpc/include/asm/nvram.h
arch/powerpc/include/asm/nvram.h
+11
-41
arch/powerpc/kernel/nvram_64.c
arch/powerpc/kernel/nvram_64.c
+160
-321
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/pgtable.c
+1
-1
arch/powerpc/platforms/chrp/time.c
arch/powerpc/platforms/chrp/time.c
+4
-0
arch/powerpc/platforms/pseries/nvram.c
arch/powerpc/platforms/pseries/nvram.c
+205
-0
未找到文件。
arch/powerpc/include/asm/nvram.h
浏览文件 @
f4b98415
...
...
@@ -10,31 +10,7 @@
#ifndef _ASM_POWERPC_NVRAM_H
#define _ASM_POWERPC_NVRAM_H
#include <linux/errno.h>
#define NVRW_CNT 0x20
#define NVRAM_HEADER_LEN 16
/* sizeof(struct nvram_header) */
#define NVRAM_BLOCK_LEN 16
#define NVRAM_MAX_REQ (2080/NVRAM_BLOCK_LEN)
#define NVRAM_MIN_REQ (1056/NVRAM_BLOCK_LEN)
#define NVRAM_AS0 0x74
#define NVRAM_AS1 0x75
#define NVRAM_DATA 0x77
/* RTC Offsets */
#define MOTO_RTC_SECONDS 0x1FF9
#define MOTO_RTC_MINUTES 0x1FFA
#define MOTO_RTC_HOURS 0x1FFB
#define MOTO_RTC_DAY_OF_WEEK 0x1FFC
#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
#define MOTO_RTC_MONTH 0x1FFE
#define MOTO_RTC_YEAR 0x1FFF
#define MOTO_RTC_CONTROLA 0x1FF8
#define MOTO_RTC_CONTROLB 0x1FF9
/* Signatures for nvram partitions */
#define NVRAM_SIG_SP 0x02
/* support processor */
#define NVRAM_SIG_OF 0x50
/* open firmware config */
#define NVRAM_SIG_FW 0x51
/* general firmware */
...
...
@@ -49,32 +25,19 @@
#define NVRAM_SIG_OS 0xa0
/* OS defined */
#define NVRAM_SIG_PANIC 0xa1
/* Apple OSX "panic" */
/* If change this size, then change the size of NVNAME_LEN */
struct
nvram_header
{
unsigned
char
signature
;
unsigned
char
checksum
;
unsigned
short
length
;
char
name
[
12
];
};
#ifdef __KERNEL__
#include <linux/errno.h>
#include <linux/list.h>
struct
nvram_partition
{
struct
list_head
partition
;
struct
nvram_header
header
;
unsigned
int
index
;
};
#ifdef CONFIG_PPC_PSERIES
extern
int
nvram_write_error_log
(
char
*
buff
,
int
length
,
unsigned
int
err_type
,
unsigned
int
err_seq
);
extern
int
nvram_read_error_log
(
char
*
buff
,
int
length
,
unsigned
int
*
err_type
,
unsigned
int
*
err_seq
);
extern
int
nvram_clear_error_log
(
void
);
extern
int
pSeries_nvram_init
(
void
);
#endif
/* CONFIG_PPC_PSERIES */
#ifdef CONFIG_MMIO_NVRAM
extern
int
mmio_nvram_init
(
void
);
...
...
@@ -85,6 +48,13 @@ static inline int mmio_nvram_init(void)
}
#endif
extern
int
__init
nvram_scan_partitions
(
void
);
extern
loff_t
nvram_create_partition
(
const
char
*
name
,
int
sig
,
int
req_size
,
int
min_size
);
extern
int
nvram_remove_partition
(
const
char
*
name
,
int
sig
);
extern
int
nvram_get_partition_size
(
loff_t
data_index
);
extern
loff_t
nvram_find_partition
(
const
char
*
name
,
int
sig
,
int
*
out_size
);
#endif
/* __KERNEL__ */
/* PowerMac specific nvram stuffs */
...
...
arch/powerpc/kernel/nvram_64.c
浏览文件 @
f4b98415
...
...
@@ -34,15 +34,26 @@
#undef DEBUG_NVRAM
static
struct
nvram_partition
*
nvram_part
;
static
long
nvram_error_log_index
=
-
1
;
static
long
nvram_error_log_size
=
0
;
#define NVRAM_HEADER_LEN sizeof(struct nvram_header)
#define NVRAM_BLOCK_LEN NVRAM_HEADER_LEN
/* If change this size, then change the size of NVNAME_LEN */
struct
nvram_header
{
unsigned
char
signature
;
unsigned
char
checksum
;
unsigned
short
length
;
/* Terminating null required only for names < 12 chars. */
char
name
[
12
];
};
struct
err_log_info
{
int
error_type
;
unsigned
int
seq_num
;
struct
nvram_partition
{
struct
list_head
partition
;
struct
nvram_header
header
;
unsigned
int
index
;
};
static
LIST_HEAD
(
nvram_partitions
);
static
loff_t
dev_nvram_llseek
(
struct
file
*
file
,
loff_t
offset
,
int
origin
)
{
int
size
;
...
...
@@ -186,14 +197,12 @@ static struct miscdevice nvram_dev = {
#ifdef DEBUG_NVRAM
static
void
__init
nvram_print_partitions
(
char
*
label
)
{
struct
list_head
*
p
;
struct
nvram_partition
*
tmp_part
;
printk
(
KERN_WARNING
"--------%s---------
\n
"
,
label
);
printk
(
KERN_WARNING
"indx
\t\t
sig
\t
chks
\t
len
\t
name
\n
"
);
list_for_each
(
p
,
&
nvram_part
->
partition
)
{
tmp_part
=
list_entry
(
p
,
struct
nvram_partition
,
partition
);
printk
(
KERN_WARNING
"%4d
\t
%02x
\t
%02x
\t
%d
\t
%s
\n
"
,
list_for_each_entry
(
tmp_part
,
&
nvram_partitions
,
partition
)
{
printk
(
KERN_WARNING
"%4d
\t
%02x
\t
%02x
\t
%d
\t
%12s
\n
"
,
tmp_part
->
index
,
tmp_part
->
header
.
signature
,
tmp_part
->
header
.
checksum
,
tmp_part
->
header
.
length
,
tmp_part
->
header
.
name
);
...
...
@@ -228,95 +237,113 @@ static unsigned char __init nvram_checksum(struct nvram_header *p)
return
c_sum
;
}
static
int
__init
nvram_remove_os_partition
(
void
)
/**
* nvram_remove_partition - Remove one or more partitions in nvram
* @name: name of the partition to remove, or NULL for a
* signature only match
* @sig: signature of the partition(s) to remove
*/
int
__init
nvram_remove_partition
(
const
char
*
name
,
int
sig
)
{
struct
list_head
*
i
;
struct
list_head
*
j
;
struct
nvram_partition
*
part
;
struct
nvram_partition
*
cur_part
;
struct
nvram_partition
*
part
,
*
prev
,
*
tmp
;
int
rc
;
list_for_each
(
i
,
&
nvram_part
->
partition
)
{
part
=
list_entry
(
i
,
struct
nvram_partition
,
partition
);
if
(
part
->
header
.
signature
!=
NVRAM_SIG_OS
)
list_for_each_entry
(
part
,
&
nvram_partitions
,
partition
)
{
if
(
part
->
header
.
signature
!=
sig
)
continue
;
/* Make os partition a free partition */
if
(
name
&&
strncmp
(
name
,
part
->
header
.
name
,
12
))
continue
;
/* Make partition a free partition */
part
->
header
.
signature
=
NVRAM_SIG_FREE
;
s
printf
(
part
->
header
.
name
,
"wwwwwwwwwwww"
);
s
trncpy
(
part
->
header
.
name
,
"wwwwwwwwwwww"
,
12
);
part
->
header
.
checksum
=
nvram_checksum
(
&
part
->
header
);
/* Merge contiguous free partitions backwards */
list_for_each_prev
(
j
,
&
part
->
partition
)
{
cur_part
=
list_entry
(
j
,
struct
nvram_partition
,
partition
);
if
(
cur_part
==
nvram_part
||
cur_part
->
header
.
signature
!=
NVRAM_SIG_FREE
)
{
break
;
}
part
->
header
.
length
+=
cur_part
->
header
.
length
;
part
->
header
.
checksum
=
nvram_checksum
(
&
part
->
header
);
part
->
index
=
cur_part
->
index
;
list_del
(
&
cur_part
->
partition
);
kfree
(
cur_part
);
j
=
&
part
->
partition
;
/* fixup our loop */
}
/* Merge contiguous free partitions forwards */
list_for_each
(
j
,
&
part
->
partition
)
{
cur_part
=
list_entry
(
j
,
struct
nvram_partition
,
partition
);
if
(
cur_part
==
nvram_part
||
cur_part
->
header
.
signature
!=
NVRAM_SIG_FREE
)
{
break
;
}
part
->
header
.
length
+=
cur_part
->
header
.
length
;
part
->
header
.
checksum
=
nvram_checksum
(
&
part
->
header
);
list_del
(
&
cur_part
->
partition
);
kfree
(
cur_part
);
j
=
&
part
->
partition
;
/* fixup our loop */
}
rc
=
nvram_write_header
(
part
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_remove_
os_
partition: nvram_write failed (%d)
\n
"
,
rc
);
printk
(
KERN_ERR
"nvram_remove_partition: nvram_write failed (%d)
\n
"
,
rc
);
return
rc
;
}
}
/* Merge contiguous ones */
prev
=
NULL
;
list_for_each_entry_safe
(
part
,
tmp
,
&
nvram_partitions
,
partition
)
{
if
(
part
->
header
.
signature
!=
NVRAM_SIG_FREE
)
{
prev
=
NULL
;
continue
;
}
if
(
prev
)
{
prev
->
header
.
length
+=
part
->
header
.
length
;
prev
->
header
.
checksum
=
nvram_checksum
(
&
part
->
header
);
rc
=
nvram_write_header
(
part
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_remove_partition: nvram_write failed (%d)
\n
"
,
rc
);
return
rc
;
}
list_del
(
&
part
->
partition
);
kfree
(
part
);
}
else
prev
=
part
;
}
return
0
;
}
/* nvram_create_os_partition
/**
* nvram_create_partition - Create a partition in nvram
* @name: name of the partition to create
* @sig: signature of the partition to create
* @req_size: size of data to allocate in bytes
* @min_size: minimum acceptable size (0 means req_size)
*
* Create a OS linux partition to buffer error logs.
* Will create a partition starting at the first free
* space found if space has enough room.
* Returns a negative error code or a positive nvram index
* of the beginning of the data area of the newly created
* partition. If you provided a min_size smaller than req_size
* you need to query for the actual size yourself after the
* call using nvram_partition_get_size().
*/
static
int
__init
nvram_create_os_partition
(
void
)
loff_t
__init
nvram_create_partition
(
const
char
*
name
,
int
sig
,
int
req_size
,
int
min_size
)
{
struct
nvram_partition
*
part
;
struct
nvram_partition
*
new_part
;
struct
nvram_partition
*
free_part
=
NULL
;
int
seq_init
[
2
]
=
{
0
,
0
}
;
static
char
nv_init_vals
[
16
]
;
loff_t
tmp_index
;
long
size
=
0
;
int
rc
;
/* Convert sizes from bytes to blocks */
req_size
=
_ALIGN_UP
(
req_size
,
NVRAM_BLOCK_LEN
)
/
NVRAM_BLOCK_LEN
;
min_size
=
_ALIGN_UP
(
min_size
,
NVRAM_BLOCK_LEN
)
/
NVRAM_BLOCK_LEN
;
/* If no minimum size specified, make it the same as the
* requested size
*/
if
(
min_size
==
0
)
min_size
=
req_size
;
if
(
min_size
>
req_size
)
return
-
EINVAL
;
/* Now add one block to each for the header */
req_size
+=
1
;
min_size
+=
1
;
/* Find a free partition that will give us the maximum needed size
If can't find one that will give us the minimum size needed */
list_for_each_entry
(
part
,
&
nvram_part
->
partition
,
partition
)
{
list_for_each_entry
(
part
,
&
nvram_part
itions
,
partition
)
{
if
(
part
->
header
.
signature
!=
NVRAM_SIG_FREE
)
continue
;
if
(
part
->
header
.
length
>=
NVRAM_MAX_REQ
)
{
size
=
NVRAM_MAX_REQ
;
if
(
part
->
header
.
length
>=
req_size
)
{
size
=
req_size
;
free_part
=
part
;
break
;
}
if
(
!
size
&&
part
->
header
.
length
>=
NVRAM_MIN_REQ
)
{
size
=
NVRAM_MIN_REQ
;
if
(
part
->
header
.
length
>
size
&&
part
->
header
.
length
>=
min_size
)
{
size
=
part
->
header
.
length
;
free_part
=
part
;
}
}
...
...
@@ -326,136 +353,95 @@ static int __init nvram_create_os_partition(void)
/* Create our OS partition */
new_part
=
kmalloc
(
sizeof
(
*
new_part
),
GFP_KERNEL
);
if
(
!
new_part
)
{
pr
intk
(
KERN_ERR
"nvram_create_os_partition: kmalloc failed
\n
"
);
pr
_err
(
"nvram_create_os_partition: kmalloc failed
\n
"
);
return
-
ENOMEM
;
}
new_part
->
index
=
free_part
->
index
;
new_part
->
header
.
signature
=
NVRAM_SIG_OS
;
new_part
->
header
.
signature
=
sig
;
new_part
->
header
.
length
=
size
;
str
cpy
(
new_part
->
header
.
name
,
"ppc64,linux"
);
str
ncpy
(
new_part
->
header
.
name
,
name
,
12
);
new_part
->
header
.
checksum
=
nvram_checksum
(
&
new_part
->
header
);
rc
=
nvram_write_header
(
new_part
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_create_os_partition: nvram_write_header "
"failed (%d)
\n
"
,
rc
);
return
rc
;
}
/* make sure and initialize to zero the sequence number and the error
type logged */
tmp_index
=
new_part
->
index
+
NVRAM_HEADER_LEN
;
rc
=
ppc_md
.
nvram_write
((
char
*
)
&
seq_init
,
sizeof
(
seq_init
),
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_create_os_partition: nvram_write "
pr_err
(
"nvram_create_os_partition: nvram_write_header "
"failed (%d)
\n
"
,
rc
);
return
rc
;
}
nvram_error_log_index
=
new_part
->
index
+
NVRAM_HEADER_LEN
;
nvram_error_log_size
=
((
part
->
header
.
length
-
1
)
*
NVRAM_BLOCK_LEN
)
-
sizeof
(
struct
err_log_info
);
list_add_tail
(
&
new_part
->
partition
,
&
free_part
->
partition
);
if
(
free_part
->
header
.
length
<=
size
)
{
/* Adjust or remove the partition we stole the space from */
if
(
free_part
->
header
.
length
>
size
)
{
free_part
->
index
+=
size
*
NVRAM_BLOCK_LEN
;
free_part
->
header
.
length
-=
size
;
free_part
->
header
.
checksum
=
nvram_checksum
(
&
free_part
->
header
);
rc
=
nvram_write_header
(
free_part
);
if
(
rc
<=
0
)
{
pr_err
(
"nvram_create_os_partition: nvram_write_header "
"failed (%d)
\n
"
,
rc
);
return
rc
;
}
}
else
{
list_del
(
&
free_part
->
partition
);
kfree
(
free_part
);
return
0
;
}
/* Adjust the partition we stole the space from */
free_part
->
index
+=
size
*
NVRAM_BLOCK_LEN
;
free_part
->
header
.
length
-=
size
;
free_part
->
header
.
checksum
=
nvram_checksum
(
&
free_part
->
header
);
rc
=
nvram_write_header
(
free_part
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_create_os_partition: nvram_write_header "
"failed (%d)
\n
"
,
rc
);
return
rc
;
/* Clear the new partition */
for
(
tmp_index
=
new_part
->
index
+
NVRAM_HEADER_LEN
;
tmp_index
<
((
size
-
1
)
*
NVRAM_BLOCK_LEN
);
tmp_index
+=
NVRAM_BLOCK_LEN
)
{
rc
=
ppc_md
.
nvram_write
(
nv_init_vals
,
NVRAM_BLOCK_LEN
,
&
tmp_index
);
if
(
rc
<=
0
)
{
pr_err
(
"nvram_create_partition: nvram_write failed (%d)
\n
"
,
rc
);
return
rc
;
}
}
return
0
;
return
new_part
->
index
+
NVRAM_HEADER_LEN
;
}
/* nvram_setup_partition
*
* This will setup the partition we need for buffering the
* error logs and cleanup partitions if needed.
*
* The general strategy is the following:
* 1.) If there is ppc64,linux partition large enough then use it.
* 2.) If there is not a ppc64,linux partition large enough, search
* for a free partition that is large enough.
* 3.) If there is not a free partition large enough remove
* _all_ OS partitions and consolidate the space.
* 4.) Will first try getting a chunk that will satisfy the maximum
* error log size (NVRAM_MAX_REQ).
* 5.) If the max chunk cannot be allocated then try finding a chunk
* that will satisfy the minum needed (NVRAM_MIN_REQ).
/**
* nvram_get_partition_size - Get the data size of an nvram partition
* @data_index: This is the offset of the start of the data of
* the partition. The same value that is returned by
* nvram_create_partition().
*/
static
int
__init
nvram_setup_partition
(
void
)
int
nvram_get_partition_size
(
loff_t
data_index
)
{
struct
list_head
*
p
;
struct
nvram_partition
*
part
;
int
rc
;
/* For now, we don't do any of this on pmac, until I
* have figured out if it's worth killing some unused stuffs
* in our nvram, as Apple defined partitions use pretty much
* all of the space
*/
if
(
machine_is
(
powermac
))
return
-
ENOSPC
;
/* see if we have an OS partition that meets our needs.
will try getting the max we need. If not we'll delete
partitions and try again. */
list_for_each
(
p
,
&
nvram_part
->
partition
)
{
part
=
list_entry
(
p
,
struct
nvram_partition
,
partition
);
if
(
part
->
header
.
signature
!=
NVRAM_SIG_OS
)
continue
;
struct
nvram_partition
*
part
;
list_for_each_entry
(
part
,
&
nvram_partitions
,
partition
)
{
if
(
part
->
index
+
NVRAM_HEADER_LEN
==
data_index
)
return
(
part
->
header
.
length
-
1
)
*
NVRAM_BLOCK_LEN
;
}
return
-
1
;
}
if
(
strcmp
(
part
->
header
.
name
,
"ppc64,linux"
))
continue
;
if
(
part
->
header
.
length
>=
NVRAM_MIN_REQ
)
{
/* found our partition */
nvram_error_log_index
=
part
->
index
+
NVRAM_HEADER_LEN
;
nvram_error_log_size
=
((
part
->
header
.
length
-
1
)
*
NVRAM_BLOCK_LEN
)
-
sizeof
(
struct
err_log_info
);
return
0
;
/**
* nvram_find_partition - Find an nvram partition by signature and name
* @name: Name of the partition or NULL for any name
* @sig: Signature to test against
* @out_size: if non-NULL, returns the size of the data part of the partition
*/
loff_t
nvram_find_partition
(
const
char
*
name
,
int
sig
,
int
*
out_size
)
{
struct
nvram_partition
*
p
;
list_for_each_entry
(
p
,
&
nvram_partitions
,
partition
)
{
if
(
p
->
header
.
signature
==
sig
&&
(
!
name
||
!
strncmp
(
p
->
header
.
name
,
name
,
12
)))
{
if
(
out_size
)
*
out_size
=
(
p
->
header
.
length
-
1
)
*
NVRAM_BLOCK_LEN
;
return
p
->
index
+
NVRAM_HEADER_LEN
;
}
}
/* try creating a partition with the free space we have */
rc
=
nvram_create_os_partition
();
if
(
!
rc
)
{
return
0
;
}
/* need to free up some space */
rc
=
nvram_remove_os_partition
();
if
(
rc
)
{
return
rc
;
}
/* create a partition in this new space */
rc
=
nvram_create_os_partition
();
if
(
rc
)
{
printk
(
KERN_ERR
"nvram_create_os_partition: Could not find a "
"NVRAM partition large enough
\n
"
);
return
rc
;
}
return
0
;
}
static
int
__init
nvram_scan_partitions
(
void
)
int
__init
nvram_scan_partitions
(
void
)
{
loff_t
cur_index
=
0
;
struct
nvram_header
phead
;
...
...
@@ -465,7 +451,7 @@ static int __init nvram_scan_partitions(void)
int
total_size
;
int
err
;
if
(
ppc_md
.
nvram_size
==
NULL
)
if
(
ppc_md
.
nvram_size
==
NULL
||
ppc_md
.
nvram_size
()
<=
0
)
return
-
ENODEV
;
total_size
=
ppc_md
.
nvram_size
();
...
...
@@ -512,12 +498,16 @@ static int __init nvram_scan_partitions(void)
memcpy
(
&
tmp_part
->
header
,
&
phead
,
NVRAM_HEADER_LEN
);
tmp_part
->
index
=
cur_index
;
list_add_tail
(
&
tmp_part
->
partition
,
&
nvram_part
->
partition
);
list_add_tail
(
&
tmp_part
->
partition
,
&
nvram_part
itions
);
cur_index
+=
phead
.
length
*
NVRAM_BLOCK_LEN
;
}
err
=
0
;
#ifdef DEBUG_NVRAM
nvram_print_partitions
(
"NVRAM Partitions"
);
#endif
out:
kfree
(
header
);
return
err
;
...
...
@@ -525,9 +515,10 @@ static int __init nvram_scan_partitions(void)
static
int
__init
nvram_init
(
void
)
{
int
error
;
int
rc
;
BUILD_BUG_ON
(
NVRAM_BLOCK_LEN
!=
16
);
if
(
ppc_md
.
nvram_size
==
NULL
||
ppc_md
.
nvram_size
()
<=
0
)
return
-
ENODEV
;
...
...
@@ -537,29 +528,6 @@ static int __init nvram_init(void)
return
rc
;
}
/* initialize our anchor for the nvram partition list */
nvram_part
=
kmalloc
(
sizeof
(
struct
nvram_partition
),
GFP_KERNEL
);
if
(
!
nvram_part
)
{
printk
(
KERN_ERR
"nvram_init: Failed kmalloc
\n
"
);
return
-
ENOMEM
;
}
INIT_LIST_HEAD
(
&
nvram_part
->
partition
);
/* Get all the NVRAM partitions */
error
=
nvram_scan_partitions
();
if
(
error
)
{
printk
(
KERN_ERR
"nvram_init: Failed nvram_scan_partitions
\n
"
);
return
error
;
}
if
(
nvram_setup_partition
())
printk
(
KERN_WARNING
"nvram_init: Could not find nvram partition"
" for nvram buffered error logging.
\n
"
);
#ifdef DEBUG_NVRAM
nvram_print_partitions
(
"NVRAM Partitions"
);
#endif
return
rc
;
}
...
...
@@ -568,135 +536,6 @@ void __exit nvram_cleanup(void)
misc_deregister
(
&
nvram_dev
);
}
#ifdef CONFIG_PPC_PSERIES
/* nvram_write_error_log
*
* We need to buffer the error logs into nvram to ensure that we have
* the failure information to decode. If we have a severe error there
* is no way to guarantee that the OS or the machine is in a state to
* get back to user land and write the error to disk. For example if
* the SCSI device driver causes a Machine Check by writing to a bad
* IO address, there is no way of guaranteeing that the device driver
* is in any state that is would also be able to write the error data
* captured to disk, thus we buffer it in NVRAM for analysis on the
* next boot.
*
* In NVRAM the partition containing the error log buffer will looks like:
* Header (in bytes):
* +-----------+----------+--------+------------+------------------+
* | signature | checksum | length | name | data |
* |0 |1 |2 3|4 15|16 length-1|
* +-----------+----------+--------+------------+------------------+
*
* The 'data' section would look like (in bytes):
* +--------------+------------+-----------------------------------+
* | event_logged | sequence # | error log |
* |0 3|4 7|8 nvram_error_log_size-1|
* +--------------+------------+-----------------------------------+
*
* event_logged: 0 if event has not been logged to syslog, 1 if it has
* sequence #: The unique sequence # for each event. (until it wraps)
* error log: The error log from event_scan
*/
int
nvram_write_error_log
(
char
*
buff
,
int
length
,
unsigned
int
err_type
,
unsigned
int
error_log_cnt
)
{
int
rc
;
loff_t
tmp_index
;
struct
err_log_info
info
;
if
(
nvram_error_log_index
==
-
1
)
{
return
-
ESPIPE
;
}
if
(
length
>
nvram_error_log_size
)
{
length
=
nvram_error_log_size
;
}
info
.
error_type
=
err_type
;
info
.
seq_num
=
error_log_cnt
;
tmp_index
=
nvram_error_log_index
;
rc
=
ppc_md
.
nvram_write
((
char
*
)
&
info
,
sizeof
(
struct
err_log_info
),
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_write_error_log: Failed nvram_write (%d)
\n
"
,
rc
);
return
rc
;
}
rc
=
ppc_md
.
nvram_write
(
buff
,
length
,
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_write_error_log: Failed nvram_write (%d)
\n
"
,
rc
);
return
rc
;
}
return
0
;
}
/* nvram_read_error_log
*
* Reads nvram for error log for at most 'length'
*/
int
nvram_read_error_log
(
char
*
buff
,
int
length
,
unsigned
int
*
err_type
,
unsigned
int
*
error_log_cnt
)
{
int
rc
;
loff_t
tmp_index
;
struct
err_log_info
info
;
if
(
nvram_error_log_index
==
-
1
)
return
-
1
;
if
(
length
>
nvram_error_log_size
)
length
=
nvram_error_log_size
;
tmp_index
=
nvram_error_log_index
;
rc
=
ppc_md
.
nvram_read
((
char
*
)
&
info
,
sizeof
(
struct
err_log_info
),
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_read_error_log: Failed nvram_read (%d)
\n
"
,
rc
);
return
rc
;
}
rc
=
ppc_md
.
nvram_read
(
buff
,
length
,
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_read_error_log: Failed nvram_read (%d)
\n
"
,
rc
);
return
rc
;
}
*
error_log_cnt
=
info
.
seq_num
;
*
err_type
=
info
.
error_type
;
return
0
;
}
/* This doesn't actually zero anything, but it sets the event_logged
* word to tell that this event is safely in syslog.
*/
int
nvram_clear_error_log
(
void
)
{
loff_t
tmp_index
;
int
clear_word
=
ERR_FLAG_ALREADY_LOGGED
;
int
rc
;
if
(
nvram_error_log_index
==
-
1
)
return
-
1
;
tmp_index
=
nvram_error_log_index
;
rc
=
ppc_md
.
nvram_write
((
char
*
)
&
clear_word
,
sizeof
(
int
),
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_clear_error_log: Failed nvram_write (%d)
\n
"
,
rc
);
return
rc
;
}
return
0
;
}
#endif
/* CONFIG_PPC_PSERIES */
module_init
(
nvram_init
);
module_exit
(
nvram_cleanup
);
MODULE_LICENSE
(
"GPL"
);
arch/powerpc/mm/pgtable.c
浏览文件 @
f4b98415
...
...
@@ -92,7 +92,7 @@ static void pte_free_rcu_callback(struct rcu_head *head)
static
void
pte_free_submit
(
struct
pte_freelist_batch
*
batch
)
{
call_rcu
(
&
batch
->
rcu
,
pte_free_rcu_callback
);
call_rcu
_sched
(
&
batch
->
rcu
,
pte_free_rcu_callback
);
}
void
pgtable_free_tlb
(
struct
mmu_gather
*
tlb
,
void
*
table
,
unsigned
shift
)
...
...
arch/powerpc/platforms/chrp/time.c
浏览文件 @
f4b98415
...
...
@@ -29,6 +29,10 @@
extern
spinlock_t
rtc_lock
;
#define NVRAM_AS0 0x74
#define NVRAM_AS1 0x75
#define NVRAM_DATA 0x77
static
int
nvram_as1
=
NVRAM_AS1
;
static
int
nvram_as0
=
NVRAM_AS0
;
static
int
nvram_data
=
NVRAM_DATA
;
...
...
arch/powerpc/platforms/pseries/nvram.c
浏览文件 @
f4b98415
...
...
@@ -22,11 +22,25 @@
#include <asm/prom.h>
#include <asm/machdep.h>
/* Max bytes to read/write in one go */
#define NVRW_CNT 0x20
static
unsigned
int
nvram_size
;
static
int
nvram_fetch
,
nvram_store
;
static
char
nvram_buf
[
NVRW_CNT
];
/* assume this is in the first 4GB */
static
DEFINE_SPINLOCK
(
nvram_lock
);
static
long
nvram_error_log_index
=
-
1
;
static
long
nvram_error_log_size
=
0
;
struct
err_log_info
{
int
error_type
;
unsigned
int
seq_num
;
};
#define NVRAM_MAX_REQ 2079
#define NVRAM_MIN_REQ 1055
#define NVRAM_LOG_PART_NAME "ibm,rtas-log"
static
ssize_t
pSeries_nvram_read
(
char
*
buf
,
size_t
count
,
loff_t
*
index
)
{
...
...
@@ -119,6 +133,197 @@ static ssize_t pSeries_nvram_get_size(void)
return
nvram_size
?
nvram_size
:
-
ENODEV
;
}
/* nvram_write_error_log
*
* We need to buffer the error logs into nvram to ensure that we have
* the failure information to decode. If we have a severe error there
* is no way to guarantee that the OS or the machine is in a state to
* get back to user land and write the error to disk. For example if
* the SCSI device driver causes a Machine Check by writing to a bad
* IO address, there is no way of guaranteeing that the device driver
* is in any state that is would also be able to write the error data
* captured to disk, thus we buffer it in NVRAM for analysis on the
* next boot.
*
* In NVRAM the partition containing the error log buffer will looks like:
* Header (in bytes):
* +-----------+----------+--------+------------+------------------+
* | signature | checksum | length | name | data |
* |0 |1 |2 3|4 15|16 length-1|
* +-----------+----------+--------+------------+------------------+
*
* The 'data' section would look like (in bytes):
* +--------------+------------+-----------------------------------+
* | event_logged | sequence # | error log |
* |0 3|4 7|8 nvram_error_log_size-1|
* +--------------+------------+-----------------------------------+
*
* event_logged: 0 if event has not been logged to syslog, 1 if it has
* sequence #: The unique sequence # for each event. (until it wraps)
* error log: The error log from event_scan
*/
int
nvram_write_error_log
(
char
*
buff
,
int
length
,
unsigned
int
err_type
,
unsigned
int
error_log_cnt
)
{
int
rc
;
loff_t
tmp_index
;
struct
err_log_info
info
;
if
(
nvram_error_log_index
==
-
1
)
{
return
-
ESPIPE
;
}
if
(
length
>
nvram_error_log_size
)
{
length
=
nvram_error_log_size
;
}
info
.
error_type
=
err_type
;
info
.
seq_num
=
error_log_cnt
;
tmp_index
=
nvram_error_log_index
;
rc
=
ppc_md
.
nvram_write
((
char
*
)
&
info
,
sizeof
(
struct
err_log_info
),
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_write_error_log: Failed nvram_write (%d)
\n
"
,
rc
);
return
rc
;
}
rc
=
ppc_md
.
nvram_write
(
buff
,
length
,
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_write_error_log: Failed nvram_write (%d)
\n
"
,
rc
);
return
rc
;
}
return
0
;
}
/* nvram_read_error_log
*
* Reads nvram for error log for at most 'length'
*/
int
nvram_read_error_log
(
char
*
buff
,
int
length
,
unsigned
int
*
err_type
,
unsigned
int
*
error_log_cnt
)
{
int
rc
;
loff_t
tmp_index
;
struct
err_log_info
info
;
if
(
nvram_error_log_index
==
-
1
)
return
-
1
;
if
(
length
>
nvram_error_log_size
)
length
=
nvram_error_log_size
;
tmp_index
=
nvram_error_log_index
;
rc
=
ppc_md
.
nvram_read
((
char
*
)
&
info
,
sizeof
(
struct
err_log_info
),
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_read_error_log: Failed nvram_read (%d)
\n
"
,
rc
);
return
rc
;
}
rc
=
ppc_md
.
nvram_read
(
buff
,
length
,
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_read_error_log: Failed nvram_read (%d)
\n
"
,
rc
);
return
rc
;
}
*
error_log_cnt
=
info
.
seq_num
;
*
err_type
=
info
.
error_type
;
return
0
;
}
/* This doesn't actually zero anything, but it sets the event_logged
* word to tell that this event is safely in syslog.
*/
int
nvram_clear_error_log
(
void
)
{
loff_t
tmp_index
;
int
clear_word
=
ERR_FLAG_ALREADY_LOGGED
;
int
rc
;
if
(
nvram_error_log_index
==
-
1
)
return
-
1
;
tmp_index
=
nvram_error_log_index
;
rc
=
ppc_md
.
nvram_write
((
char
*
)
&
clear_word
,
sizeof
(
int
),
&
tmp_index
);
if
(
rc
<=
0
)
{
printk
(
KERN_ERR
"nvram_clear_error_log: Failed nvram_write (%d)
\n
"
,
rc
);
return
rc
;
}
return
0
;
}
/* pseries_nvram_init_log_partition
*
* This will setup the partition we need for buffering the
* error logs and cleanup partitions if needed.
*
* The general strategy is the following:
* 1.) If there is log partition large enough then use it.
* 2.) If there is none large enough, search
* for a free partition that is large enough.
* 3.) If there is not a free partition large enough remove
* _all_ OS partitions and consolidate the space.
* 4.) Will first try getting a chunk that will satisfy the maximum
* error log size (NVRAM_MAX_REQ).
* 5.) If the max chunk cannot be allocated then try finding a chunk
* that will satisfy the minum needed (NVRAM_MIN_REQ).
*/
static
int
__init
pseries_nvram_init_log_partition
(
void
)
{
loff_t
p
;
int
size
;
/* Scan nvram for partitions */
nvram_scan_partitions
();
/* Lookg for ours */
p
=
nvram_find_partition
(
NVRAM_LOG_PART_NAME
,
NVRAM_SIG_OS
,
&
size
);
/* Found one but too small, remove it */
if
(
p
&&
size
<
NVRAM_MIN_REQ
)
{
pr_info
(
"nvram: Found too small "
NVRAM_LOG_PART_NAME
" partition"
",removing it..."
);
nvram_remove_partition
(
NVRAM_LOG_PART_NAME
,
NVRAM_SIG_OS
);
p
=
0
;
}
/* Create one if we didn't find */
if
(
!
p
)
{
p
=
nvram_create_partition
(
NVRAM_LOG_PART_NAME
,
NVRAM_SIG_OS
,
NVRAM_MAX_REQ
,
NVRAM_MIN_REQ
);
/* No room for it, try to get rid of any OS partition
* and try again
*/
if
(
p
==
-
ENOSPC
)
{
pr_info
(
"nvram: No room to create "
NVRAM_LOG_PART_NAME
" partition, deleting all OS partitions..."
);
nvram_remove_partition
(
NULL
,
NVRAM_SIG_OS
);
p
=
nvram_create_partition
(
NVRAM_LOG_PART_NAME
,
NVRAM_SIG_OS
,
NVRAM_MAX_REQ
,
NVRAM_MIN_REQ
);
}
}
if
(
p
<=
0
)
{
pr_err
(
"nvram: Failed to find or create "
NVRAM_LOG_PART_NAME
" partition, err %d
\n
"
,
(
int
)
p
);
return
0
;
}
nvram_error_log_index
=
p
;
nvram_error_log_size
=
nvram_get_partition_size
(
p
)
-
sizeof
(
struct
err_log_info
);
return
0
;
}
machine_arch_initcall
(
pseries
,
pseries_nvram_init_log_partition
);
int
__init
pSeries_nvram_init
(
void
)
{
struct
device_node
*
nvram
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录