mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-26 16:41:25 +00:00
powerpc/nvram: Generalize code for OS partitions in NVRAM
Adapt the functions used to create and write to the RTAS-log partition to work with any OS-type partition. Signed-off-by: Jim Keniston <jkenisto@us.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
6dd2270029
commit
0f4ac13236
3 changed files with 113 additions and 64 deletions
|
@ -51,7 +51,8 @@ static inline int mmio_nvram_init(void)
|
||||||
extern int __init nvram_scan_partitions(void);
|
extern int __init nvram_scan_partitions(void);
|
||||||
extern loff_t nvram_create_partition(const char *name, int sig,
|
extern loff_t nvram_create_partition(const char *name, int sig,
|
||||||
int req_size, int min_size);
|
int req_size, int min_size);
|
||||||
extern int nvram_remove_partition(const char *name, int sig);
|
extern int nvram_remove_partition(const char *name, int sig,
|
||||||
|
const char *exceptions[]);
|
||||||
extern int nvram_get_partition_size(loff_t data_index);
|
extern int nvram_get_partition_size(loff_t data_index);
|
||||||
extern loff_t nvram_find_partition(const char *name, int sig, int *out_size);
|
extern loff_t nvram_find_partition(const char *name, int sig, int *out_size);
|
||||||
|
|
||||||
|
|
|
@ -237,22 +237,45 @@ static unsigned char __init nvram_checksum(struct nvram_header *p)
|
||||||
return c_sum;
|
return c_sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per the criteria passed via nvram_remove_partition(), should this
|
||||||
|
* partition be removed? 1=remove, 0=keep
|
||||||
|
*/
|
||||||
|
static int nvram_can_remove_partition(struct nvram_partition *part,
|
||||||
|
const char *name, int sig, const char *exceptions[])
|
||||||
|
{
|
||||||
|
if (part->header.signature != sig)
|
||||||
|
return 0;
|
||||||
|
if (name) {
|
||||||
|
if (strncmp(name, part->header.name, 12))
|
||||||
|
return 0;
|
||||||
|
} else if (exceptions) {
|
||||||
|
const char **except;
|
||||||
|
for (except = exceptions; *except; except++) {
|
||||||
|
if (!strncmp(*except, part->header.name, 12))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nvram_remove_partition - Remove one or more partitions in nvram
|
* nvram_remove_partition - Remove one or more partitions in nvram
|
||||||
* @name: name of the partition to remove, or NULL for a
|
* @name: name of the partition to remove, or NULL for a
|
||||||
* signature only match
|
* signature only match
|
||||||
* @sig: signature of the partition(s) to remove
|
* @sig: signature of the partition(s) to remove
|
||||||
|
* @exceptions: When removing all partitions with a matching signature,
|
||||||
|
* leave these alone.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int __init nvram_remove_partition(const char *name, int sig)
|
int __init nvram_remove_partition(const char *name, int sig,
|
||||||
|
const char *exceptions[])
|
||||||
{
|
{
|
||||||
struct nvram_partition *part, *prev, *tmp;
|
struct nvram_partition *part, *prev, *tmp;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
list_for_each_entry(part, &nvram_partitions, partition) {
|
list_for_each_entry(part, &nvram_partitions, partition) {
|
||||||
if (part->header.signature != sig)
|
if (!nvram_can_remove_partition(part, name, sig, exceptions))
|
||||||
continue;
|
|
||||||
if (name && strncmp(name, part->header.name, 12))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Make partition a free partition */
|
/* Make partition a free partition */
|
||||||
|
|
|
@ -30,17 +30,30 @@ static int nvram_fetch, nvram_store;
|
||||||
static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
|
static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
|
||||||
static DEFINE_SPINLOCK(nvram_lock);
|
static DEFINE_SPINLOCK(nvram_lock);
|
||||||
|
|
||||||
static long nvram_error_log_index = -1;
|
|
||||||
static long nvram_error_log_size = 0;
|
|
||||||
|
|
||||||
struct err_log_info {
|
struct err_log_info {
|
||||||
int error_type;
|
int error_type;
|
||||||
unsigned int seq_num;
|
unsigned int seq_num;
|
||||||
};
|
};
|
||||||
#define NVRAM_MAX_REQ 2079
|
|
||||||
#define NVRAM_MIN_REQ 1055
|
|
||||||
|
|
||||||
#define NVRAM_LOG_PART_NAME "ibm,rtas-log"
|
struct nvram_os_partition {
|
||||||
|
const char *name;
|
||||||
|
int req_size; /* desired size, in bytes */
|
||||||
|
int min_size; /* minimum acceptable size (0 means req_size) */
|
||||||
|
long size; /* size of data portion of partition */
|
||||||
|
long index; /* offset of data portion of partition */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct nvram_os_partition rtas_log_partition = {
|
||||||
|
.name = "ibm,rtas-log",
|
||||||
|
.req_size = 2079,
|
||||||
|
.min_size = 1055,
|
||||||
|
.index = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *pseries_nvram_os_partitions[] = {
|
||||||
|
"ibm,rtas-log",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
|
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
|
||||||
{
|
{
|
||||||
|
@ -134,7 +147,7 @@ static ssize_t pSeries_nvram_get_size(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* nvram_write_error_log
|
/* nvram_write_os_partition, nvram_write_error_log
|
||||||
*
|
*
|
||||||
* We need to buffer the error logs into nvram to ensure that we have
|
* 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
|
* the failure information to decode. If we have a severe error there
|
||||||
|
@ -156,48 +169,55 @@ static ssize_t pSeries_nvram_get_size(void)
|
||||||
* The 'data' section would look like (in bytes):
|
* The 'data' section would look like (in bytes):
|
||||||
* +--------------+------------+-----------------------------------+
|
* +--------------+------------+-----------------------------------+
|
||||||
* | event_logged | sequence # | error log |
|
* | event_logged | sequence # | error log |
|
||||||
* |0 3|4 7|8 nvram_error_log_size-1|
|
* |0 3|4 7|8 error_log_size-1|
|
||||||
* +--------------+------------+-----------------------------------+
|
* +--------------+------------+-----------------------------------+
|
||||||
*
|
*
|
||||||
* event_logged: 0 if event has not been logged to syslog, 1 if it has
|
* 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)
|
* sequence #: The unique sequence # for each event. (until it wraps)
|
||||||
* error log: The error log from event_scan
|
* error log: The error log from event_scan
|
||||||
*/
|
*/
|
||||||
int nvram_write_error_log(char * buff, int length,
|
int nvram_write_os_partition(struct nvram_os_partition *part, char * buff,
|
||||||
unsigned int err_type, unsigned int error_log_cnt)
|
int length, unsigned int err_type, unsigned int error_log_cnt)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
loff_t tmp_index;
|
loff_t tmp_index;
|
||||||
struct err_log_info info;
|
struct err_log_info info;
|
||||||
|
|
||||||
if (nvram_error_log_index == -1) {
|
if (part->index == -1) {
|
||||||
return -ESPIPE;
|
return -ESPIPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length > nvram_error_log_size) {
|
if (length > part->size) {
|
||||||
length = nvram_error_log_size;
|
length = part->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.error_type = err_type;
|
info.error_type = err_type;
|
||||||
info.seq_num = error_log_cnt;
|
info.seq_num = error_log_cnt;
|
||||||
|
|
||||||
tmp_index = nvram_error_log_index;
|
tmp_index = part->index;
|
||||||
|
|
||||||
rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
|
rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
|
pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ppc_md.nvram_write(buff, length, &tmp_index);
|
rc = ppc_md.nvram_write(buff, length, &tmp_index);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
|
pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nvram_write_error_log(char * buff, int length,
|
||||||
|
unsigned int err_type, unsigned int error_log_cnt)
|
||||||
|
{
|
||||||
|
return nvram_write_os_partition(&rtas_log_partition, buff, length,
|
||||||
|
err_type, error_log_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
/* nvram_read_error_log
|
/* nvram_read_error_log
|
||||||
*
|
*
|
||||||
* Reads nvram for error log for at most 'length'
|
* Reads nvram for error log for at most 'length'
|
||||||
|
@ -209,13 +229,13 @@ int nvram_read_error_log(char * buff, int length,
|
||||||
loff_t tmp_index;
|
loff_t tmp_index;
|
||||||
struct err_log_info info;
|
struct err_log_info info;
|
||||||
|
|
||||||
if (nvram_error_log_index == -1)
|
if (rtas_log_partition.index == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (length > nvram_error_log_size)
|
if (length > rtas_log_partition.size)
|
||||||
length = nvram_error_log_size;
|
length = rtas_log_partition.size;
|
||||||
|
|
||||||
tmp_index = nvram_error_log_index;
|
tmp_index = rtas_log_partition.index;
|
||||||
|
|
||||||
rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
|
rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
|
@ -244,10 +264,10 @@ int nvram_clear_error_log(void)
|
||||||
int clear_word = ERR_FLAG_ALREADY_LOGGED;
|
int clear_word = ERR_FLAG_ALREADY_LOGGED;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (nvram_error_log_index == -1)
|
if (rtas_log_partition.index == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
tmp_index = nvram_error_log_index;
|
tmp_index = rtas_log_partition.index;
|
||||||
|
|
||||||
rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
|
rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
|
||||||
if (rc <= 0) {
|
if (rc <= 0) {
|
||||||
|
@ -258,23 +278,25 @@ int nvram_clear_error_log(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pseries_nvram_init_log_partition
|
/* pseries_nvram_init_os_partition
|
||||||
*
|
*
|
||||||
* This will setup the partition we need for buffering the
|
* This sets up a partition with an "OS" signature.
|
||||||
* error logs and cleanup partitions if needed.
|
|
||||||
*
|
*
|
||||||
* The general strategy is the following:
|
* The general strategy is the following:
|
||||||
* 1.) If there is log partition large enough then use it.
|
* 1.) If a partition with the indicated name already exists...
|
||||||
* 2.) If there is none large enough, search
|
* - If it's large enough, use it.
|
||||||
* for a free partition that is large enough.
|
* - Otherwise, recycle it and keep going.
|
||||||
* 3.) If there is not a free partition large enough remove
|
* 2.) Search for a free partition that is large enough.
|
||||||
* _all_ OS partitions and consolidate the space.
|
* 3.) If there's not a free partition large enough, recycle any obsolete
|
||||||
* 4.) Will first try getting a chunk that will satisfy the maximum
|
* OS partitions and try again.
|
||||||
* error log size (NVRAM_MAX_REQ).
|
* 4.) Will first try getting a chunk that will satisfy the requested size.
|
||||||
* 5.) If the max chunk cannot be allocated then try finding a chunk
|
* 5.) If a chunk of the requested size cannot be allocated, then try finding
|
||||||
* that will satisfy the minum needed (NVRAM_MIN_REQ).
|
* a chunk that will satisfy the minum needed.
|
||||||
|
*
|
||||||
|
* Returns 0 on success, else -1.
|
||||||
*/
|
*/
|
||||||
static int __init pseries_nvram_init_log_partition(void)
|
static int __init pseries_nvram_init_os_partition(struct nvram_os_partition
|
||||||
|
*part)
|
||||||
{
|
{
|
||||||
loff_t p;
|
loff_t p;
|
||||||
int size;
|
int size;
|
||||||
|
@ -282,47 +304,50 @@ static int __init pseries_nvram_init_log_partition(void)
|
||||||
/* Scan nvram for partitions */
|
/* Scan nvram for partitions */
|
||||||
nvram_scan_partitions();
|
nvram_scan_partitions();
|
||||||
|
|
||||||
/* Lookg for ours */
|
/* Look for ours */
|
||||||
p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size);
|
p = nvram_find_partition(part->name, NVRAM_SIG_OS, &size);
|
||||||
|
|
||||||
/* Found one but too small, remove it */
|
/* Found one but too small, remove it */
|
||||||
if (p && size < NVRAM_MIN_REQ) {
|
if (p && size < part->min_size) {
|
||||||
pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition"
|
pr_info("nvram: Found too small %s partition,"
|
||||||
",removing it...");
|
" removing it...\n", part->name);
|
||||||
nvram_remove_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS);
|
nvram_remove_partition(part->name, NVRAM_SIG_OS, NULL);
|
||||||
p = 0;
|
p = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create one if we didn't find */
|
/* Create one if we didn't find */
|
||||||
if (!p) {
|
if (!p) {
|
||||||
p = nvram_create_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS,
|
p = nvram_create_partition(part->name, NVRAM_SIG_OS,
|
||||||
NVRAM_MAX_REQ, NVRAM_MIN_REQ);
|
part->req_size, part->min_size);
|
||||||
/* No room for it, try to get rid of any OS partition
|
|
||||||
* and try again
|
|
||||||
*/
|
|
||||||
if (p == -ENOSPC) {
|
if (p == -ENOSPC) {
|
||||||
pr_info("nvram: No room to create "NVRAM_LOG_PART_NAME
|
pr_info("nvram: No room to create %s partition, "
|
||||||
" partition, deleting all OS partitions...");
|
"deleting any obsolete OS partitions...\n",
|
||||||
nvram_remove_partition(NULL, NVRAM_SIG_OS);
|
part->name);
|
||||||
p = nvram_create_partition(NVRAM_LOG_PART_NAME,
|
nvram_remove_partition(NULL, NVRAM_SIG_OS,
|
||||||
NVRAM_SIG_OS, NVRAM_MAX_REQ,
|
pseries_nvram_os_partitions);
|
||||||
NVRAM_MIN_REQ);
|
p = nvram_create_partition(part->name, NVRAM_SIG_OS,
|
||||||
|
part->req_size, part->min_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p <= 0) {
|
if (p <= 0) {
|
||||||
pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME
|
pr_err("nvram: Failed to find or create %s"
|
||||||
" partition, err %d\n", (int)p);
|
" partition, err %d\n", part->name, (int)p);
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvram_error_log_index = p;
|
part->index = p;
|
||||||
nvram_error_log_size = nvram_get_partition_size(p) -
|
part->size = nvram_get_partition_size(p) - sizeof(struct err_log_info);
|
||||||
sizeof(struct err_log_info);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
machine_arch_initcall(pseries, pseries_nvram_init_log_partition);
|
|
||||||
|
static int __init pseries_nvram_init_log_partitions(void)
|
||||||
|
{
|
||||||
|
(void) pseries_nvram_init_os_partition(&rtas_log_partition);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
machine_arch_initcall(pseries, pseries_nvram_init_log_partitions);
|
||||||
|
|
||||||
int __init pSeries_nvram_init(void)
|
int __init pSeries_nvram_init(void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue