* [PATCH 04/13] powerpc/nvram: Ensure that the partition header/block size is right
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Use BUILD_BUG_ON to ensure the structure representing a partition
header have the right size.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index a5a5587..f753882 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -565,6 +565,8 @@ 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;
--
1.7.1
^ permalink raw reply related
* [PATCH 03/13] powerpc/nvram: nvram_create_partitions() now uses bytes
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This converts nvram_create_partition() to use a size in bytes
rather than blocks. It does the appropriate alignment internally
The size passed is also the data size (ie. doesn't include the
header anymore).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 20 ++++++++++++++------
1 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 9e13335..a5a5587 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -34,10 +34,10 @@
#undef DEBUG_NVRAM
-#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_HEADER_LEN sizeof(struct nvram_header)
+#define NVRAM_BLOCK_LEN NVRAM_HEADER_LEN
+#define NVRAM_MAX_REQ 2079
+#define NVRAM_MIN_REQ 1055
/* If change this size, then change the size of NVNAME_LEN */
struct nvram_header {
@@ -311,7 +311,7 @@ static int __init nvram_remove_os_partition(void)
* 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 to allocate preferrably
+ * @req_size: size of data to allocate in bytes
* @min_size: minimum acceptable size (0 means req_size)
*/
static int __init nvram_create_partition(const char *name, int sig,
@@ -325,12 +325,20 @@ static int __init nvram_create_partition(const char *name, int sig,
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;
+ /* 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) {
@@ -450,7 +458,7 @@ static int __init nvram_setup_partition(void)
if (strcmp(part->header.name, "ppc64,linux"))
continue;
- if (part->header.length >= NVRAM_MIN_REQ) {
+ if ((part->header.length - 1) * NVRAM_BLOCK_LEN >= NVRAM_MIN_REQ) {
/* found our partition */
nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
nvram_error_log_size = ((part->header.length - 1) *
--
1.7.1
^ permalink raw reply related
* [PATCH 05/13] powerpc/nvram: Completely clear a new partition
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
When creating a partition, we clear it entirely rather than
just the first two words since the previous code was rather
specific to the pseries log partition format.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 19 ++++++++++---------
1 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index f753882..02737e6 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -320,7 +320,7 @@ static int __init nvram_create_partition(const char *name, int sig,
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;
@@ -379,14 +379,15 @@ static int __init nvram_create_partition(const char *name, int sig,
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 "
- "failed (%d)\n", rc);
- return rc;
+ /* Clear the 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;
+ }
}
nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN;
--
1.7.1
^ permalink raw reply related
* [PATCH 07/13] powerpc/nvram: Improve partition removal
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Existing code is nasty, has bugs etc... rewrite the function
more simply, and make it take the signature and optional
name of the partitions to remove as arguments, thus making
it a more generic utility.
We also try to remove a log partition that we find and is too
small rather than creating a duplicate.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 91 +++++++++++++++++++---------------------
1 files changed, 43 insertions(+), 48 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index eabee7c..6dd2700 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -247,61 +247,54 @@ 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
+ */
+
+static 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_part->partition, 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;
sprintf(part->header.name, "wwwwwwwwwwww");
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_part->partition, 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;
@@ -484,17 +477,19 @@ static int __init nvram_setup_partition(void)
NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
return 0;
}
+
+ /* Found one but it's too small, remove it */
+ nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS);
}
/* try creating a partition with the free space we have */
rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
NVRAM_MAX_REQ, NVRAM_MIN_REQ);
if (rc < 0) {
- /* need to free up some space */
- rc = nvram_remove_os_partition();
- if (rc)
- return rc;
- /* create a partition in this new space */
+ /* need to free up some space, remove any "OS" partition */
+ nvram_remove_partition(NULL, NVRAM_SIG_OS);
+
+ /* Try again */
rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
NVRAM_MAX_REQ, NVRAM_MIN_REQ);
if (rc < 0) {
--
1.7.1
^ permalink raw reply related
* [PATCH 09/13] powerpc/nvram: Change nvram_setup_partition() to use new helper
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This changes the function to use nvram_find_partition() instead
of doing the lookup "by hand". It also makes some of the logic
clearer and prints out more useful diagnostic information.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 71 ++++++++++++++++++----------------------
1 files changed, 32 insertions(+), 39 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 01e6844..76f546b 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -469,9 +469,8 @@ loff_t nvram_find_partition(const char *name, int sig, int *out_size)
*/
static int __init nvram_setup_partition(void)
{
- struct list_head * p;
- struct nvram_partition * part;
- int rc;
+ loff_t p;
+ int size;
/* For now, we don't do any of this on pmac, until I
* have figured out if it's worth killing some unused stuffs
@@ -481,48 +480,42 @@ static int __init nvram_setup_partition(void)
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;
-
- if (strcmp(part->header.name, "ppc64,linux"))
- continue;
-
- if ((part->header.length - 1) * NVRAM_BLOCK_LEN >= 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;
- }
+ p = nvram_find_partition("ppc64,linux", NVRAM_SIG_OS, &size);
- /* Found one but it's too small, remove it */
+ /* Found one but too small, remove it */
+ if (p && size < NVRAM_MIN_REQ) {
+ pr_info("nvram: Found too small ppc64,linux partition"
+ ",removing it...");
nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS);
+ p = 0;
}
-
- /* try creating a partition with the free space we have */
- rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
- NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- if (rc < 0) {
- /* need to free up some space, remove any "OS" partition */
- nvram_remove_partition(NULL, NVRAM_SIG_OS);
-
- /* Try again */
- rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
- NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- if (rc < 0) {
- pr_err("nvram_create_partition: Could not find"
- " enough space in NVRAM for partition\n");
- return rc;
+
+ /* Create one if we didn't find */
+ if (!p) {
+ p = nvram_create_partition("ppc64,linux", 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 ppc64,linux"
+ " partition, deleting all OS partitions...");
+ nvram_remove_partition(NULL, NVRAM_SIG_OS);
+ p = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
+ NVRAM_MAX_REQ, NVRAM_MIN_REQ);
}
}
+
+ if (p <= 0) {
+ pr_err("nvram: Failed to find or create ppc64,linux"
+ " 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);
- nvram_error_log_index = rc;
- nvram_error_log_size = nvram_get_partition_size(rc) - sizeof(struct err_log_info);
return 0;
}
--
1.7.1
^ permalink raw reply related
* [PATCH 11/13] powerpc/nvram: Rename ppc64, linux partition to ibm, rtas-log
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
I'm not aware of any userspace tool accessing it by its name anyways,
it's read back by the kernel itself on the next boot to get back
older log entries
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/platforms/pseries/nvram.c | 23 +++++++++++++----------
1 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 55a7141..7e828ba 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -40,6 +40,8 @@ struct err_log_info {
#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)
{
unsigned int i;
@@ -262,8 +264,8 @@ int nvram_clear_error_log(void)
* 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
+ * 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.
@@ -281,34 +283,35 @@ static int __init pseries_nvram_init_log_partition(void)
nvram_scan_partitions();
/* Lookg for ours */
- p = nvram_find_partition("ppc64,linux", NVRAM_SIG_OS, &size);
+ 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 ppc64,linux partition"
+ pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition"
",removing it...");
- nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS);
+ 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("ppc64,linux", NVRAM_SIG_OS,
+ 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 ppc64,linux"
+ 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("ppc64,linux", NVRAM_SIG_OS,
- NVRAM_MAX_REQ, NVRAM_MIN_REQ);
+ 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 ppc64,linux"
+ pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME
" partition, err %d\n", (int)p);
return 0;
}
--
1.7.1
^ permalink raw reply related
* [PATCH 12/13] powerpc/nvram: Fix NVRAM partition list setup
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Jim Keniston, jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Jim Keniston <jkenisto@us.ibm.com>
Simplify creation and use of the NVRAM partition list.
Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 26 ++++++++------------------
1 files changed, 8 insertions(+), 18 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 125d86c..b8a50fa 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -51,7 +51,7 @@ struct nvram_partition {
unsigned int index;
};
-static struct nvram_partition * nvram_part;
+static LIST_HEAD(nvram_partitions);
static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
{
@@ -196,13 +196,11 @@ 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\tsig\tchks\tlen\tname\n");
- list_for_each(p, &nvram_part->partition) {
- tmp_part = list_entry(p, struct nvram_partition, partition);
+ list_for_each_entry(tmp_part, &nvram_partitions, partition) {
printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%s\n",
tmp_part->index, tmp_part->header.signature,
tmp_part->header.checksum, tmp_part->header.length,
@@ -250,7 +248,7 @@ int __init nvram_remove_partition(const char *name, int sig)
struct nvram_partition *part, *prev, *tmp;
int rc;
- list_for_each_entry(part, &nvram_part->partition, partition) {
+ list_for_each_entry(part, &nvram_partitions, partition) {
if (part->header.signature != sig)
continue;
if (name && strncmp(name, part->header.name, 12))
@@ -269,7 +267,7 @@ int __init nvram_remove_partition(const char *name, int sig)
/* Merge contiguous ones */
prev = NULL;
- list_for_each_entry_safe(part, tmp, &nvram_part->partition, partition) {
+ list_for_each_entry_safe(part, tmp, &nvram_partitions, partition) {
if (part->header.signature != NVRAM_SIG_FREE) {
prev = NULL;
continue;
@@ -333,7 +331,7 @@ loff_t __init nvram_create_partition(const char *name, int sig,
/* 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_partitions, partition) {
if (part->header.signature != NVRAM_SIG_FREE)
continue;
@@ -412,7 +410,7 @@ int nvram_get_partition_size(loff_t data_index)
{
struct nvram_partition *part;
- list_for_each_entry(part, &nvram_part->partition, partition) {
+ list_for_each_entry(part, &nvram_partitions, partition) {
if (part->index + NVRAM_HEADER_LEN == data_index)
return (part->header.length - 1) * NVRAM_BLOCK_LEN;
}
@@ -430,7 +428,7 @@ loff_t nvram_find_partition(const char *name, int sig, int *out_size)
{
struct nvram_partition *p;
- list_for_each_entry(p, &nvram_part->partition, partition) {
+ list_for_each_entry(p, &nvram_partitions, partition) {
if (p->header.signature == sig &&
(!name || !strncmp(p->header.name, name, 12))) {
if (out_size)
@@ -452,14 +450,6 @@ int __init nvram_scan_partitions(void)
int total_size;
int err;
- /* 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);
-
if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
return -ENODEV;
total_size = ppc_md.nvram_size();
@@ -507,7 +497,7 @@ 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_partitions);
cur_index += phead.length * NVRAM_BLOCK_LEN;
}
--
1.7.1
^ permalink raw reply related
* [PATCH 10/13] powerpc/nvram: Move the log partition stuff to pseries
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
The nvram log partition stuff currently in nvram_64.c is really
pseries specific. It isn't actually used on anything else (despite
the fact that we ran the code to setup the partition on anything
except powermac) and the log format is specific to pseries RTAS
implementation. So move it where it belongs
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/include/asm/nvram.h | 10 +-
arch/powerpc/kernel/nvram_64.c | 254 +++-----------------------------
arch/powerpc/platforms/pseries/nvram.c | 200 +++++++++++++++++++++++++
3 files changed, 227 insertions(+), 237 deletions(-)
diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index 459dc09..92efe67 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -30,13 +30,14 @@
#include <linux/errno.h>
#include <linux/list.h>
+#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);
@@ -47,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 */
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 76f546b..125d86c 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -36,8 +36,6 @@
#define NVRAM_HEADER_LEN sizeof(struct nvram_header)
#define NVRAM_BLOCK_LEN NVRAM_HEADER_LEN
-#define NVRAM_MAX_REQ 2079
-#define NVRAM_MIN_REQ 1055
/* If change this size, then change the size of NVNAME_LEN */
struct nvram_header {
@@ -54,13 +52,6 @@ struct nvram_partition {
};
static struct nvram_partition * nvram_part;
-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;
-};
static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
{
@@ -254,7 +245,7 @@ static unsigned char __init nvram_checksum(struct nvram_header *p)
* @sig: signature of the partition(s) to remove
*/
-static int __init nvram_remove_partition(const char *name, int sig)
+int __init nvram_remove_partition(const char *name, int sig)
{
struct nvram_partition *part, *prev, *tmp;
int rc;
@@ -313,8 +304,8 @@ static int __init nvram_remove_partition(const char *name, int sig)
* you need to query for the actual size yourself after the
* call using nvram_partition_get_size().
*/
-static loff_t __init nvram_create_partition(const char *name, int sig,
- int req_size, int min_size)
+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;
@@ -417,7 +408,7 @@ static loff_t __init nvram_create_partition(const char *name, int sig,
* the partition. The same value that is returned by
* nvram_create_partition().
*/
-static int nvram_get_partition_size(loff_t data_index)
+int nvram_get_partition_size(loff_t data_index)
{
struct nvram_partition *part;
@@ -451,75 +442,7 @@ loff_t nvram_find_partition(const char *name, int sig, int *out_size)
return 0;
}
-/* 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).
- */
-static int __init nvram_setup_partition(void)
-{
- loff_t p;
- int size;
-
- /* 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;
-
- p = nvram_find_partition("ppc64,linux", NVRAM_SIG_OS, &size);
-
- /* Found one but too small, remove it */
- if (p && size < NVRAM_MIN_REQ) {
- pr_info("nvram: Found too small ppc64,linux partition"
- ",removing it...");
- nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS);
- p = 0;
- }
-
- /* Create one if we didn't find */
- if (!p) {
- p = nvram_create_partition("ppc64,linux", 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 ppc64,linux"
- " partition, deleting all OS partitions...");
- nvram_remove_partition(NULL, NVRAM_SIG_OS);
- p = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
- NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- }
- }
-
- if (p <= 0) {
- pr_err("nvram: Failed to find or create ppc64,linux"
- " 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;
-}
-
-static int __init nvram_scan_partitions(void)
+int __init nvram_scan_partitions(void)
{
loff_t cur_index = 0;
struct nvram_header phead;
@@ -529,7 +452,15 @@ static int __init nvram_scan_partitions(void)
int total_size;
int err;
- if (ppc_md.nvram_size == NULL)
+ /* 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);
+
+ if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
return -ENODEV;
total_size = ppc_md.nvram_size();
@@ -582,6 +513,10 @@ static int __init nvram_scan_partitions(void)
}
err = 0;
+#ifdef DEBUG_NVRAM
+ nvram_print_partitions("NVRAM Partitions");
+#endif
+
out:
kfree(header);
return err;
@@ -589,7 +524,6 @@ static int __init nvram_scan_partitions(void)
static int __init nvram_init(void)
{
- int error;
int rc;
BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16);
@@ -603,29 +537,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;
}
@@ -634,135 +545,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");
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 2a1ef5c..55a7141 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -30,6 +30,16 @@ 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
+
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
{
unsigned int i;
@@ -121,6 +131,196 @@ 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 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).
+ */
+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("ppc64,linux", NVRAM_SIG_OS, &size);
+
+ /* Found one but too small, remove it */
+ if (p && size < NVRAM_MIN_REQ) {
+ pr_info("nvram: Found too small ppc64,linux partition"
+ ",removing it...");
+ nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS);
+ p = 0;
+ }
+
+ /* Create one if we didn't find */
+ if (!p) {
+ p = nvram_create_partition("ppc64,linux", 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 ppc64,linux"
+ " partition, deleting all OS partitions...");
+ nvram_remove_partition(NULL, NVRAM_SIG_OS);
+ p = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
+ NVRAM_MAX_REQ, NVRAM_MIN_REQ);
+ }
+ }
+
+ if (p <= 0) {
+ pr_err("nvram: Failed to find or create ppc64,linux"
+ " 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;
--
1.7.1
^ permalink raw reply related
* [PATCH 13/13] powerpc/nvram: Handle partition names >= 12 chars
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Jim Keniston, jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Jim Keniston <jkenisto@us.ibm.com>
The name field in the nvram_header can be < 12 chars, null-terminated,
or 12 chars without the null. Handle this safely.
Signed-off-by: Jim Keniston <jkenisto@us.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index b8a50fa..bb12b32 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -42,6 +42,7 @@ struct nvram_header {
unsigned char signature;
unsigned char checksum;
unsigned short length;
+ /* Terminating null required only for names < 12 chars. */
char name[12];
};
@@ -201,7 +202,7 @@ static void __init nvram_print_partitions(char * label)
printk(KERN_WARNING "--------%s---------\n", label);
printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
list_for_each_entry(tmp_part, &nvram_partitions, partition) {
- printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%s\n",
+ 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);
@@ -256,7 +257,7 @@ int __init nvram_remove_partition(const char *name, int sig)
/* Make partition a free partition */
part->header.signature = NVRAM_SIG_FREE;
- sprintf(part->header.name, "wwwwwwwwwwww");
+ strncpy(part->header.name, "wwwwwwwwwwww", 12);
part->header.checksum = nvram_checksum(&part->header);
rc = nvram_write_header(part);
if (rc <= 0) {
--
1.7.1
^ permalink raw reply related
* [PATCH 08/13] powerpc/nvram: Add nvram_find_partition()
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 6dd2700..01e6844 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -429,6 +429,28 @@ static int nvram_get_partition_size(loff_t data_index)
}
+/**
+ * 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_part->partition, 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;
+ }
+ }
+ return 0;
+}
+
/* nvram_setup_partition
*
* This will setup the partition we need for buffering the
--
1.7.1
^ permalink raw reply related
* [PATCH 06/13] powerpc/nvram: Shuffle code around in nvram_create_partition()
From: benh @ 2010-11-30 5:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: jkensito
In-Reply-To: <1291096063-14386-1-git-send-email-benh@kernel.crashing.org>
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This error log stuff is really pseries specific. As a first step we move
the initialization of these variables to the caller of
nvram_create_partition(), which is also slightly reorganized so we
setup the free partition before we clear the new partition, so the
chance of an error during clear leaving us with invalid headers
is lessened.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/nvram_64.c | 108 +++++++++++++++++++++++-----------------
1 files changed, 62 insertions(+), 46 deletions(-)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 02737e6..eabee7c 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -313,9 +313,15 @@ static int __init nvram_remove_os_partition(void)
* @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)
+ *
+ * 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_partition(const char *name, int sig,
- int req_size, int min_size)
+static 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;
@@ -334,6 +340,8 @@ static int __init nvram_create_partition(const char *name, int sig,
*/
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;
@@ -362,7 +370,7 @@ static int __init nvram_create_partition(const char *name, int sig,
/* Create our OS partition */
new_part = kmalloc(sizeof(*new_part), GFP_KERNEL);
if (!new_part) {
- printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n");
+ pr_err("nvram_create_os_partition: kmalloc failed\n");
return -ENOMEM;
}
@@ -374,12 +382,29 @@ static int __init nvram_create_partition(const char *name, int sig,
rc = nvram_write_header(new_part);
if (rc <= 0) {
- printk(KERN_ERR "nvram_create_os_partition: nvram_write_header "
- "failed (%d)\n", rc);
+ pr_err("nvram_create_os_partition: nvram_write_header "
+ "failed (%d)\n", rc);
return rc;
}
+ list_add_tail(&new_part->partition, &free_part->partition);
+
+ /* 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);
+ }
- /* Clear the partition */
+ /* 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) {
@@ -390,31 +415,24 @@ static int __init nvram_create_partition(const char *name, int sig,
}
}
- 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) {
- list_del(&free_part->partition);
- kfree(free_part);
- return 0;
- }
+ return new_part->index + NVRAM_HEADER_LEN;
+}
- /* 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);
+/**
+ * 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 nvram_get_partition_size(loff_t data_index)
+{
+ struct nvram_partition *part;
- 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;
+ list_for_each_entry(part, &nvram_part->partition, partition) {
+ if (part->index + NVRAM_HEADER_LEN == data_index)
+ return (part->header.length - 1) * NVRAM_BLOCK_LEN;
}
-
- return 0;
+ return -1;
}
@@ -469,30 +487,28 @@ static int __init nvram_setup_partition(void)
}
/* try creating a partition with the free space we have */
- rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
+ rc = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS,
NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- 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_partition("ppc64,linux", NVRAM_SIG_OS,
- NVRAM_MAX_REQ, NVRAM_MIN_REQ);
- if (rc) {
- printk(KERN_ERR "nvram_create_partition: Could not find a "
- "NVRAM partition large enough\n");
- return rc;
+ if (rc < 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_partition("ppc64,linux", NVRAM_SIG_OS,
+ NVRAM_MAX_REQ, NVRAM_MIN_REQ);
+ if (rc < 0) {
+ pr_err("nvram_create_partition: Could not find"
+ " enough space in NVRAM for partition\n");
+ return rc;
+ }
}
+ nvram_error_log_index = rc;
+ nvram_error_log_size = nvram_get_partition_size(rc) - sizeof(struct err_log_info);
return 0;
}
-
static int __init nvram_scan_partitions(void)
{
loff_t cur_index = 0;
--
1.7.1
^ permalink raw reply related
* Re: [v4] ppc44x:PHY fixup for USB on canyonlands board
From: Milton Miller @ 2010-11-30 9:11 UTC (permalink / raw)
To: Rupjyoti Sarmah; +Cc: linuxppc-dev, rsarmah, linux-kernel
In-Reply-To: <201011291313.oATDD1AF028975@amcc.com>
I prepared these comments for v1, but aparently forgot to send them,
so I'll do so now.
On Mon, 29 Nov 2010 about 03:13:01 -0000, Rupjyoti Sarmah wrote:
> This fix is a reset for USB PHY that requires some amount of time for power to be stable on Canyonlands.
>
> Signed-off-by: Rupjyoti Sarmah <rsarmah@apm.com>
>
> ---
> index a303703..3c5d63c 100644
> --- a/arch/powerpc/boot/dts/canyonlands.dts
> +++ b/arch/powerpc/boot/dts/canyonlands.dts
> @@ -224,6 +224,13 @@
> };
> };
>
> + cpld@2,0 {
> + #address-cells = <1>;
> + #size-cells = <1>;
why does this node have #address-cells and #size-cells but no children?
> + compatible = "amcc,ppc460ex-bcsr";
> + reg = <2 0x0 0x9>;
> + };
> +
> ndfc@3,0 {
> compatible = "ibm,ndfc";
> reg = <0x00000003 0x00000000 0x00002000>;
..
> diff --git a/arch/powerpc/platforms/44x/canyonlands.c b/arch/powerpc/platforms/44x/canyonlands.c
> new file mode 100644
> index 0000000..4917c31
> --- /dev/null
> +++ b/arch/powerpc/platforms/44x/canyonlands.c
> @@ -0,0 +1,120 @@
> +
> +static __initdata struct of_device_id ppc44x_of_bus[] = {
..
> +static int __init ppc44x_device_probe(void)
> +{
> + of_platform_bus_probe(NULL, ppc44x_of_bus, NULL);
> +
> + return 0;
> +}
> +machine_device_initcall(canyonlands, ppc44x_device_probe);
> +
> +/* Using this code only for the Canyonlands board. */
> +
> +static int __init ppc44x_probe(void)
> +{
> + unsigned long root = of_get_flat_dt_root();
> + if (of_flat_dt_is_compatible(root, "amcc,canyonlands")) {
> + ppc_pci_set_flags(PPC_PCI_REASSIGN_ALL_RSRC);
> + return 1;
> + }
> + return 0;
> +}
> +
> +/* USB PHY fixup code on Canyonlands kit. */
All of the above have ppc44x prefix, but have been copied to this
canyonlands file. While there is no build error because they
are all static it will be less confusing if they had a canyonlands
prefix instead.
> +
> +static int __init ppc460ex_canyonlands_fixup(void)
> +{
> + u8 __iomem *bcsr ;
> + void __iomem *vaddr;
> + struct device_node *np;
> +
> + np = of_find_compatible_node(NULL, NULL, "amcc,ppc460ex-bcsr");
> + if (!np) {
> + printk(KERN_ERR "failed did not find amcc, ppc460ex bcsr node\n");
> + return -ENODEV;
> + }
> +
> + bcsr = of_iomap(np, 0);
> + of_node_put(np);
> +
> + if (!bcsr) {
> + printk(KERN_CRIT "Could not remap bcsr\n");
> + return -ENODEV;
> + }
> +
> + np = of_find_compatible_node(NULL, NULL, "ibm,ppc4xx-gpio");
> + vaddr = of_iomap(np, 0);
> + if (!vaddr) {
> + printk(KERN_CRIT "Could not get gpio node address\n");
> + return -ENODEV;
> + }
> + /* Disable USB, through the BCSR7 bits */
> + setbits8(&bcsr[7], BCSR_USB_EN);
> +
> + /* Wait for a while after reset */
> + msleep(100);
> +
> + /* Enable USB here */
> + clrbits8(&bcsr[7], BCSR_USB_EN);
> +
> + /*
> + * Configure multiplexed gpio16 and gpio19 as alternate1 output
> + * source after USB reset.This configuration is done through GPIO0_TSRH
> + * and GPIO0_OSRH bits 0:1 and 6:7.
Missing spaces before the second sentence.
Rather then telling us which bits are being set, which is fairly
obvoius from the code, it would be more helpful to say what
alternate1 output source means.
I'm curious why you set these after the reset when they were not
set before. Should they be set to something else temporarly during
the reset?
> + */
> + setbits32((vaddr + GPIO0_OSRH), 0x42000000);
> + setbits32((vaddr + GPIO0_TSRH), 0x42000000);
> + of_node_put(np);
> + return 0;
The error paths in this function leave incorrect refcounts on the
nodes, and no path does of_unmap of the regions even though the
variables with the address goes out of scope.
> +}
> +machine_device_initcall(canyonlands, ppc460ex_canyonlands_fixup);
> +define_machine(canyonlands) {
> + .name = "Canyonlands",
> + .probe = ppc44x_probe,
> + .progress = udbg_progress,
> + .init_IRQ = uic_init_tree,
> + .get_irq = uic_get_irq,
> + .restart = ppc4xx_reset_system,
> + .calibrate_decr = generic_calibrate_decr,
> +};
Also, you shouldn't need the select PPC44x_SIMPLE in the CANYONLANDS
stanza in arch/powerpc/platforms/44x/Kconfig.
milton
^ permalink raw reply
* Re: [PATCH] powerpc: fix call to subpage_protection()
From: Milton Miller @ 2010-11-30 11:06 UTC (permalink / raw)
To: Jim Keniston; +Cc: Michael Neuling <mikeyatneuling.org>, linuxppc-dev
In-Reply-To: <1290110779.32570.9.camel@pasglop>
On Fri Nov 19 about 07:06:19 EST in 2010, Benjamin Herrenschmidt wrote:
> On Thu, 2010-11-18 at 10:23 -0800, Jim Keniston wrote:
> > FWIW, this failure isn't an obstacle for me. I'm in no way attached to
> > my legacy configuration; pseries_defconfig is fine for me. On the other
> > hand, I can continue testing fixes, and/or make my system available to
> > other IBMers when I'm not using it, if you want to continue to pursue
> > this problem.
> From the look of it your "legacy" config is lacking the necessary
> storage drivers...
>
Looking closer, it would appear he intended to get them from initramfs
but unpacking it failed. Pulling from his log in the original message:
> >
> > Calling ibm,client-architecture-support... not implemented
> > command line: root=/dev/disk/by-id/scsi-SIBM_ST373453LC_3HW1CQ1400007445Q2A4-part3 quiet profile=2 sysrq=1 insmod=sym53c8xx insmod=ipr crashkernel=256M-:128M loglevel=8
> >
> > memory layout at init:
> > memory_limit : 0000000000000000 (16 MB aligned)
> > alloc_bottom : 0000000003550000
> > alloc_top : 0000000008000000
> > alloc_top_hi : 0000000070000000
> > amo_top : 0000000008000000
> > ram_top : 0000000070000000
> > instantiating rtas at 0x00000000076a0000... done
> > boot cpu hw idx 0
> > starting cpu hw idx 2... done
> > copying OF device tree...
> > Building dt strings...
> > Building dt structure...
> > Device tree strings 0x0000000003560000 -> 0x000000000356129c
> > Device tree struct 0x0000000003570000 -> 0x0000000003580000
..
> > Found initrd at 0xc000000002d00000:0xc00000000354e28a
..
> > NET: Registered protocol family 1
> > PCI: CLS 128 bytes, default 128
> > Unpacking initramfs...
> > Initramfs unpacking failed: read error
"read error" occurs in lib/decompress_inflate.c if the fill routine
returns a negative count, which would inlclude a NULL fill pointer like
init/initramfs.c.
Maybe this debugging patch (against 2.6.35, applys with small offset to
2.6.37-rc4) can help isolate the corruption?
From: Milton Miller <miltonm.bga.com>
initramfs: show input and output offsets on unpacking failures
When the initramfs input is corrupted, having the pointer to the buffer
segment being decompressed, and the decompress input and output byte
counts from the compressed stream can help isolate the source of the
corruption.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
init/initramfs.c | 5 +++++
1 file changed, 5 insertions(+)
Index: sim/init/initramfs.c
===================================================================
--- sim.orig/init/initramfs.c 2009-07-13 18:44:56.000000000 -0500
+++ sim/init/initramfs.c 2009-07-13 18:59:32.000000000 -0500
@@ -384,6 +384,9 @@ static int __init write_buffer(char *buf
return len - count;
}
+static unsigned my_inptr; /* index of next byte to be processed in inbuf */
+static unsigned bytes_out; /* count of chars processed from current archive */
+
static int __init flush_buffer(void *bufv, unsigned len)
{
char *buf = (char *) bufv;
@@ -393,6 +396,7 @@ static int __init flush_buffer(void *buf
return -1;
while ((written = write_buffer(buf, len)) < len && !message) {
char c = buf[written];
+ bytes_out += written;
if (c == '0') {
buf += written;
len -= written;
@@ -407,8 +411,6 @@ static int __init flush_buffer(void *buf
return origLen;
}
-static unsigned my_inptr; /* index of next byte to be processed in inbuf */
-
#include <linux/decompress/generic.h>
static char * __init unpack_to_rootfs(char *buf, unsigned len)
@@ -430,6 +432,8 @@ static char * __init unpack_to_rootfs(ch
message = NULL;
while (!message && len) {
loff_t saved_offset = this_header;
+ bytes_out = 0;
+ my_inptr = 0;
if (*buf == '0' && !(this_header & 3)) {
state = Start;
written = write_buffer(buf, len);
@@ -462,6 +466,9 @@ static char * __init unpack_to_rootfs(ch
buf += my_inptr;
len -= my_inptr;
}
+ if (message) {
+ printk(KERN_ERR "Failed unpacking at %p input %d output %d \n",buf - my_inptr, my_inptr, bytes_out);
+ }
dir_utime();
kfree(name_buf);
kfree(symlink_buf);
^ permalink raw reply
* Re: [PATCH] powerpc: fix call to subpage_protection()
From: Milton Miller @ 2010-11-30 11:08 UTC (permalink / raw)
To: Jim Keniston; +Cc: Michael Neuling, linuxppc-dev
In-Reply-To: <1290110779.32570.9.camel@pasglop>
[fixed Michael Neuling's address]
On Fri Nov 19 about 07:06:19 EST in 2010, Benjamin Herrenschmidt wrote:
> On Thu, 2010-11-18 at 10:23 -0800, Jim Keniston wrote:
> > FWIW, this failure isn't an obstacle for me. I'm in no way attached to
> > my legacy configuration; pseries_defconfig is fine for me. On the other
> > hand, I can continue testing fixes, and/or make my system available to
> > other IBMers when I'm not using it, if you want to continue to pursue
> > this problem.
> From the look of it your "legacy" config is lacking the necessary
> storage drivers...
>
Looking closer, it would appear he intended to get them from initramfs
but unpacking it failed. Pulling from his log in the original message:
> >
> > Calling ibm,client-architecture-support... not implemented
> > command line: root=/dev/disk/by-id/scsi-SIBM_ST373453LC_3HW1CQ1400007445Q2A4-part3 quiet profile=2 sysrq=1 insmod=sym53c8xx insmod=ipr crashkernel=256M-:128M loglevel=8
> >
> > memory layout at init:
> > memory_limit : 0000000000000000 (16 MB aligned)
> > alloc_bottom : 0000000003550000
> > alloc_top : 0000000008000000
> > alloc_top_hi : 0000000070000000
> > amo_top : 0000000008000000
> > ram_top : 0000000070000000
> > instantiating rtas at 0x00000000076a0000... done
> > boot cpu hw idx 0
> > starting cpu hw idx 2... done
> > copying OF device tree...
> > Building dt strings...
> > Building dt structure...
> > Device tree strings 0x0000000003560000 -> 0x000000000356129c
> > Device tree struct 0x0000000003570000 -> 0x0000000003580000
..
> > Found initrd at 0xc000000002d00000:0xc00000000354e28a
..
> > NET: Registered protocol family 1
> > PCI: CLS 128 bytes, default 128
> > Unpacking initramfs...
> > Initramfs unpacking failed: read error
"read error" occurs in lib/decompress_inflate.c if the fill routine
returns a negative count, which would inlclude a NULL fill pointer like
init/initramfs.c.
Maybe this debugging patch (against 2.6.35, applys with small offset to
2.6.37-rc4) can help isolate the corruption?
From: Milton Miller <miltonm.bga.com>
initramfs: show input and output offsets on unpacking failures
When the initramfs input is corrupted, having the pointer to the buffer
segment being decompressed, and the decompress input and output byte
counts from the compressed stream can help isolate the source of the
corruption.
Signed-off-by: Milton Miller <miltonm@bga.com>
---
init/initramfs.c | 5 +++++
1 file changed, 5 insertions(+)
Index: sim/init/initramfs.c
===================================================================
--- sim.orig/init/initramfs.c 2009-07-13 18:44:56.000000000 -0500
+++ sim/init/initramfs.c 2009-07-13 18:59:32.000000000 -0500
@@ -384,6 +384,9 @@ static int __init write_buffer(char *buf
return len - count;
}
+static unsigned my_inptr; /* index of next byte to be processed in inbuf */
+static unsigned bytes_out; /* count of chars processed from current archive */
+
static int __init flush_buffer(void *bufv, unsigned len)
{
char *buf = (char *) bufv;
@@ -393,6 +396,7 @@ static int __init flush_buffer(void *buf
return -1;
while ((written = write_buffer(buf, len)) < len && !message) {
char c = buf[written];
+ bytes_out += written;
if (c == '0') {
buf += written;
len -= written;
@@ -407,8 +411,6 @@ static int __init flush_buffer(void *buf
return origLen;
}
-static unsigned my_inptr; /* index of next byte to be processed in inbuf */
-
#include <linux/decompress/generic.h>
static char * __init unpack_to_rootfs(char *buf, unsigned len)
@@ -430,6 +432,8 @@ static char * __init unpack_to_rootfs(ch
message = NULL;
while (!message && len) {
loff_t saved_offset = this_header;
+ bytes_out = 0;
+ my_inptr = 0;
if (*buf == '0' && !(this_header & 3)) {
state = Start;
written = write_buffer(buf, len);
@@ -462,6 +466,9 @@ static char * __init unpack_to_rootfs(ch
buf += my_inptr;
len -= my_inptr;
}
+ if (message) {
+ printk(KERN_ERR "Failed unpacking at %p input %d output %d \n",buf - my_inptr, my_inptr, bytes_out);
+ }
dir_utime();
kfree(name_buf);
kfree(symlink_buf);
^ permalink raw reply
* [PATCH] drivers: char: hvc: add arm JTAG DCC console support
From: Daniel Walker @ 2010-11-30 19:25 UTC (permalink / raw)
To: linux-kernel
Cc: Randy Dunlap, Daniel Walker, Mike Frysinger, Arnd Bergmann,
Nicolas Pitre, Tony Lindgren, linux-arm-msm, Greg Kroah-Hartman,
FUJITA Tomonori, Andrew Morton, linuxppc-dev, Alan Cox
This driver adds a basic console that uses the arm JTAG
DCC to transfer data back and forth. It has support for
ARMv6 and ARMv7.
This console is created under the HVC driver, and should be named
/dev/hvcX (or /dev/hvc0 for example).
Cc: Tony Lindgren <tony@atomide.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Nicolas Pitre <nico@fluxnic.net>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
---
drivers/char/Kconfig | 9 +++
drivers/char/Makefile | 1 +
drivers/char/hvc_dcc.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 143 insertions(+), 0 deletions(-)
create mode 100644 drivers/char/hvc_dcc.c
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 43d3395..d4a7776 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -682,6 +682,15 @@ config HVC_UDBG
select HVC_DRIVER
default n
+config HVC_DCC
+ bool "ARM JTAG DCC console"
+ depends on ARM
+ select HVC_DRIVER
+ help
+ This console uses the JTAG DCC on ARM to create a console under the HVC
+ driver. This console is used through a JTAG only on ARM. If you don't have
+ a JTAG then you probably don't want this option.
+
config VIRTIO_CONSOLE
tristate "Virtio console"
depends on VIRTIO
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index ba53ec9..fa0b824 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_TILE) += hvc_tile.o
+obj-$(CONFIG_HVC_DCC) += hvc_dcc.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
diff --git a/drivers/char/hvc_dcc.c b/drivers/char/hvc_dcc.c
new file mode 100644
index 0000000..6470f63
--- /dev/null
+++ b/drivers/char/hvc_dcc.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <asm/processor.h>
+
+#include "hvc_console.h"
+
+/* DCC Status Bits */
+#define DCC_STATUS_RX (1 << 30)
+#define DCC_STATUS_TX (1 << 29)
+
+static inline u32 __dcc_getstatus(void)
+{
+ u32 __ret;
+
+ asm("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
+ : "=r" (__ret) : : "cc");
+
+ return __ret;
+}
+
+
+#if defined(CONFIG_CPU_V7)
+static inline char __dcc_getchar(void)
+{
+ char __c;
+
+ asm("get_wait: mrc p14, 0, pc, c0, c1, 0 \n\
+ bne get_wait \n\
+ mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
+ : "=r" (__c) : : "cc");
+
+ return __c;
+}
+#else
+static inline char __dcc_getchar(void)
+{
+ char __c;
+
+ asm("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
+ : "=r" (__c));
+
+ return __c;
+}
+#endif
+
+#if defined(CONFIG_CPU_V7)
+static inline void __dcc_putchar(char c)
+{
+ asm("put_wait: mrc p14, 0, pc, c0, c1, 0 \n\
+ bcs put_wait \n\
+ mcr p14, 0, %0, c0, c5, 0 "
+ : : "r" (c) : "cc");
+}
+#else
+static inline void __dcc_putchar(char c)
+{
+ asm("mcr p14, 0, %0, c0, c5, 0 @ write a char"
+ : /* no output register */
+ : "r" (c));
+}
+#endif
+
+static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ while (__dcc_getstatus() & DCC_STATUS_TX)
+ cpu_relax();
+
+ __dcc_putchar((char)(buf[i] & 0xFF));
+ }
+
+ return count;
+}
+
+static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
+{
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ int c = -1;
+
+ if (__dcc_getstatus() & DCC_STATUS_RX)
+ c = __dcc_getchar();
+ if (c < 0)
+ break;
+ buf[i] = c;
+ }
+
+ return i;
+}
+
+static const struct hv_ops hvc_dcc_get_put_ops = {
+ .get_chars = hvc_dcc_get_chars,
+ .put_chars = hvc_dcc_put_chars,
+};
+
+static int __init hvc_dcc_console_init(void)
+{
+ hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
+ return 0;
+}
+console_initcall(hvc_dcc_console_init);
+
+static int __init hvc_dcc_init(void)
+{
+ hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
+ return 0;
+}
+device_initcall(hvc_dcc_init);
--
1.7.1
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply related
* RE: [PATCH 1/2][v4] fsl_rio: move machine_check handler into machine_check_e500 & machine_check_e500mc
From: Bounine, Alexandre @ 2010-11-30 20:47 UTC (permalink / raw)
To: Shaohui Xie, linuxppc-dev; +Cc: akpm, Kumar Gala
In-Reply-To: <1290063452-20873-1-git-send-email-b21989@freescale.com>
Tested on my 8548/RIO setup - works as expected.
Alex.
> -----Original Message-----
> From: Shaohui Xie [mailto:b21989@freescale.com]
> Sent: Thursday, November 18, 2010 1:58 AM
> To: linuxppc-dev@lists.ozlabs.org
> Cc: akpm@linux-foundation.org; Shaohui Xie; Li Yang; Kumar Gala; Roy
Zang; Bounine, Alexandre
> Subject: [PATCH 1/2][v4] fsl_rio: move machine_check handler into
machine_check_e500 &
> machine_check_e500mc
>=20
^ permalink raw reply
* RE: [PATCH 2/2][v3] rapidio, powerpc/85xx: Error interrupt handler for sRIO.
From: Bounine, Alexandre @ 2010-11-30 20:48 UTC (permalink / raw)
To: Shaohui Xie, linuxppc-dev; +Cc: akpm, Kumar Gala
In-Reply-To: <1290063473-20950-1-git-send-email-b21989@freescale.com>
Applies correctly now. Lab tested on 8548/RIO setup.
Alex.=20
> -----Original Message-----
> From: Shaohui Xie [mailto:b21989@freescale.com]
> Sent: Thursday, November 18, 2010 1:58 AM
> To: linuxppc-dev@lists.ozlabs.org
> Cc: akpm@linux-foundation.org; Shaohui Xie; Li Yang; Kumar Gala; Roy
Zang; Bounine, Alexandre
> Subject: [PATCH 2/2][v3] rapidio, powerpc/85xx: Error interrupt
handler for sRIO.
>=20
> The sRIO controller reports errors to the core with one signal, it
uses
> register EPWISR to provides the core quick access to where the error
occurred.
> The EPWISR indicates that there are 4 interrupts sources, port1,
port2, message
> unit and port write receive, but the sRIO driver does not support
port2
> for now, still the handler takes care of port2.
> Currently the handler only clear error status without any recovery.
^ permalink raw reply
* Re: [PATCH] powerpc: fix call to subpage_protection()
From: Jim Keniston @ 2010-11-30 20:55 UTC (permalink / raw)
To: Milton Miller; +Cc: Michael Neuling, linuxppc-dev
In-Reply-To: <mdm-initramfs-debug-fix@mdm.bga.com>
On Tue, 2010-11-30 at 05:08 -0600, Milton Miller wrote:
> [fixed Michael Neuling's address]
>
> On Fri Nov 19 about 07:06:19 EST in 2010, Benjamin Herrenschmidt wrote:
> > On Thu, 2010-11-18 at 10:23 -0800, Jim Keniston wrote:
> > > FWIW, this failure isn't an obstacle for me. I'm in no way attached to
> > > my legacy configuration; pseries_defconfig is fine for me. On the other
> > > hand, I can continue testing fixes, and/or make my system available to
> > > other IBMers when I'm not using it, if you want to continue to pursue
> > > this problem.
>
> > From the look of it your "legacy" config is lacking the necessary
> > storage drivers...
> >
>
> Looking closer, it would appear he intended to get them from initramfs
> but unpacking it failed. Pulling from his log in the original message:
Bingo! Not only was I using a "legacy" .config file, I'd also copied
and pasted an older yaboot.conf entry without updating the initrd-size
clause. The initrd-size value was apparently big enough until I enabled
the extra DEBUG code. Mr. Miller's diagnostic message reported the
unpacking failure at just a few bytes past the specified initrd-size.
Adjusting the initrd-size to match the actual size of the file enables
the kernel to boot.
So... cockpit error. Very sorry for the fuss, but thanks for the
detective work.
As for Mr. Miller's patch...
Tested-by: Jim Keniston <jkenisto@us.ibm.com>
Jim
>
> > >
> > > Calling ibm,client-architecture-support... not implemented
> > > command line: root=/dev/disk/by-id/scsi-SIBM_ST373453LC_3HW1CQ1400007445Q2A4-part3 quiet profile=2 sysrq=1 insmod=sym53c8xx insmod=ipr crashkernel=256M-:128M loglevel=8
> > >
> > > memory layout at init:
> > > memory_limit : 0000000000000000 (16 MB aligned)
> > > alloc_bottom : 0000000003550000
> > > alloc_top : 0000000008000000
> > > alloc_top_hi : 0000000070000000
> > > amo_top : 0000000008000000
> > > ram_top : 0000000070000000
> > > instantiating rtas at 0x00000000076a0000... done
> > > boot cpu hw idx 0
> > > starting cpu hw idx 2... done
> > > copying OF device tree...
> > > Building dt strings...
> > > Building dt structure...
> > > Device tree strings 0x0000000003560000 -> 0x000000000356129c
> > > Device tree struct 0x0000000003570000 -> 0x0000000003580000
> ..
> > > Found initrd at 0xc000000002d00000:0xc00000000354e28a
> ..
> > > NET: Registered protocol family 1
> > > PCI: CLS 128 bytes, default 128
> > > Unpacking initramfs...
> > > Initramfs unpacking failed: read error
>
> "read error" occurs in lib/decompress_inflate.c if the fill routine
> returns a negative count, which would inlclude a NULL fill pointer like
> init/initramfs.c.
>
>
> Maybe this debugging patch (against 2.6.35, applys with small offset to
> 2.6.37-rc4) can help isolate the corruption?
>
> From: Milton Miller <miltonm.bga.com>
> initramfs: show input and output offsets on unpacking failures
>
> When the initramfs input is corrupted, having the pointer to the buffer
> segment being decompressed, and the decompress input and output byte
> counts from the compressed stream can help isolate the source of the
> corruption.
>
> Signed-off-by: Milton Miller <miltonm@bga.com>
>
> ---
> init/initramfs.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> Index: sim/init/initramfs.c
> ===================================================================
> --- sim.orig/init/initramfs.c 2009-07-13 18:44:56.000000000 -0500
> +++ sim/init/initramfs.c 2009-07-13 18:59:32.000000000 -0500
> @@ -384,6 +384,9 @@ static int __init write_buffer(char *buf
> return len - count;
> }
>
> +static unsigned my_inptr; /* index of next byte to be processed in inbuf */
> +static unsigned bytes_out; /* count of chars processed from current archive */
> +
> static int __init flush_buffer(void *bufv, unsigned len)
> {
> char *buf = (char *) bufv;
> @@ -393,6 +396,7 @@ static int __init flush_buffer(void *buf
> return -1;
> while ((written = write_buffer(buf, len)) < len && !message) {
> char c = buf[written];
> + bytes_out += written;
> if (c == '0') {
> buf += written;
> len -= written;
> @@ -407,8 +411,6 @@ static int __init flush_buffer(void *buf
> return origLen;
> }
>
> -static unsigned my_inptr; /* index of next byte to be processed in inbuf */
> -
> #include <linux/decompress/generic.h>
>
> static char * __init unpack_to_rootfs(char *buf, unsigned len)
> @@ -430,6 +432,8 @@ static char * __init unpack_to_rootfs(ch
> message = NULL;
> while (!message && len) {
> loff_t saved_offset = this_header;
> + bytes_out = 0;
> + my_inptr = 0;
> if (*buf == '0' && !(this_header & 3)) {
> state = Start;
> written = write_buffer(buf, len);
> @@ -462,6 +466,9 @@ static char * __init unpack_to_rootfs(ch
> buf += my_inptr;
> len -= my_inptr;
> }
> + if (message) {
> + printk(KERN_ERR "Failed unpacking at %p input %d output %d \n",buf - my_inptr, my_inptr, bytes_out);
> + }
> dir_utime();
> kfree(name_buf);
> kfree(symlink_buf);
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [PATCH] drivers: char: hvc: add arm JTAG DCC console support
From: Nicolas Pitre @ 2010-11-30 19:57 UTC (permalink / raw)
To: Daniel Walker
Cc: Randy Dunlap, Mike Frysinger, Arnd Bergmann, Tony Lindgren,
linux-arm-msm, Greg Kroah-Hartman, linux-kernel, FUJITA Tomonori,
Andrew Morton, linuxppc-dev, Alan Cox
In-Reply-To: <1291145141-18301-1-git-send-email-dwalker@codeaurora.org>
On Tue, 30 Nov 2010, Daniel Walker wrote:
> This driver adds a basic console that uses the arm JTAG
> DCC to transfer data back and forth. It has support for
> ARMv6 and ARMv7.
>
> This console is created under the HVC driver, and should be named
> /dev/hvcX (or /dev/hvc0 for example).
>
> Cc: Tony Lindgren <tony@atomide.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Nicolas Pitre <nico@fluxnic.net>
> Cc: Greg Kroah-Hartman <gregkh@suse.de>
> Cc: Mike Frysinger <vapier@gentoo.org>
> Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
This doesn't support both ARMv6 and ARMv7 at run time, but this can
trivially be added later when needed.
Nicolas
^ permalink raw reply
* Re: [PATCH] drivers: char: hvc: add arm JTAG DCC console support
From: Arnd Bergmann @ 2010-11-30 21:17 UTC (permalink / raw)
To: Nicolas Pitre
Cc: Randy Dunlap, Daniel Walker, Mike Frysinger, Tony Lindgren,
linux-arm-msm, Greg Kroah-Hartman, linux-kernel, FUJITA Tomonori,
Andrew Morton, linuxppc-dev, Alan Cox
In-Reply-To: <alpine.LFD.2.00.1011301455400.9313@xanadu.home>
On Tuesday 30 November 2010, Nicolas Pitre wrote:
> > Cc: Tony Lindgren <tony@atomide.com>
> > Cc: Arnd Bergmann <arnd@arndb.de>
> > Cc: Nicolas Pitre <nico@fluxnic.net>
> > Cc: Greg Kroah-Hartman <gregkh@suse.de>
> > Cc: Mike Frysinger <vapier@gentoo.org>
> > Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
>
> Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
> This doesn't support both ARMv6 and ARMv7 at run time, but this can
> trivially be added later when needed.
I was about to make a similar comment when I saw yours ;-)
^ permalink raw reply
* Re: [PATCH v2] PPC4xx: Adding PCI(E) MSI support
From: Tirumala Marri @ 2010-11-30 23:07 UTC (permalink / raw)
To: michael; +Cc: linuxppc-dev
In-Reply-To: <1291080609.2648.102.camel@concordia>
[-- Attachment #1: Type: text/plain, Size: 515 bytes --]
On Mon, Nov 29, 2
>
> >
> > My apologies in the delay here. I was on holiday for a while and never
> > got back to review this. A few notes below.
> >
> > Also, I've added a few patches from Victor for suspend/idle support in
> > my next branch that cause a minor conflict with this one. It's not a
> > big deal to fix, but if you rework the patch for the comments, rebasing
> > it to my next branch would be appreciated.
>
Sure thanks for reviewing. I will fix the suggested changes and send the
updated patch.
[-- Attachment #2: Type: text/html, Size: 767 bytes --]
^ permalink raw reply
* Re: [RFC PATCH 3/7 v2] ppc: do not search for dma-window property on dlpar remove
From: Nishanth Aravamudan @ 2010-12-01 0:30 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: sonnyrao, miltonm, Paul Mackerras, Anton Blanchard, linuxppc-dev
In-Reply-To: <1290994721.32570.219.camel@pasglop>
On 29.11.2010 [12:38:41 +1100], Benjamin Herrenschmidt wrote:
> On Tue, 2010-10-26 at 20:35 -0700, Nishanth Aravamudan wrote:
> > The iommu_table pointer in the pci auxiliary struct of device_node has
> > not been used by the iommu ops since the dma refactor of
> > 12d04eef927bf61328af2c7cbe756c96f98ac3bf, however this code still uses
> > it to find tables for dlpar. By only setting the PCI_DN iommu_table
> > pointer on nodes with dma window properties, we will be able to quickly
> > find the node for later checks, and can remove the table without looking
> > for the the dma window property on dlpar remove.
>
> The answer might well be yes but are we sure this works with busses &
> devices that don't have a dma,window ? ie. we always properly look for
> parents when assigning pci devices arch_data iommu table ? Did you test
> it ? :-) (Best way is to find a card with a P2P bridge on it).
I haven't tested this particular case. I'm getting a machine to do so
now, though.
Thanks,
Nish
--
Nishanth Aravamudan <nacc@us.ibm.com>
IBM Linux Technology Center
^ permalink raw reply
* Re: [PATCH 14/15] ppc64 iommu: use coherent_dma_mask for alloc_coherent
From: Nishanth Aravamudan @ 2010-12-01 0:31 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras, Milton Miller
In-Reply-To: <1290992296.32570.215.camel@pasglop>
On 29.11.2010 [11:58:16 +1100], Benjamin Herrenschmidt wrote:
> On Wed, 2010-09-15 at 11:05 -0700, Nishanth Aravamudan wrote:
> > The IOMMU code has been passing the dma-mask instead of the
> > coherent_dma_mask to the iommu allocator. Coherent allocations should
> > be made using the coherent_dma_mask.
>
> Won't that break macio devices too ? afaik, they don't set
> coherent_dma_mask. Have you tried booting on a G5 with iommu enabled ?
>
> (It may not be broken, just asking...)
I have not tried this. I unfortunately do not have immediate access to a
G5 to test on, but will ask around.
Thanks,
Nish
--
Nishanth Aravamudan <nacc@us.ibm.com>
IBM Linux Technology Center
^ permalink raw reply
* Re: ppc_set_hwdebug vs ptrace_set_debugreg
From: K.Prasad @ 2010-12-01 4:37 UTC (permalink / raw)
To: Andreas Schwab; +Cc: linuxppc-dev, Dave Kleikamp, Srikar Dronamraju
In-Reply-To: <m38w0c77vs.fsf@linux-m68k.org>
On Mon, Nov 29, 2010 at 11:15:51AM +0100, Andreas Schwab wrote:
> "K.Prasad" <prasad@linux.vnet.ibm.com> writes:
>
> > Although ppc_set_hwdebug() can set DABR through set_dabr() in
> > arch/powerpc/kernel/process.c, it is good to have it converted to use
> > register_user_hw_breakpoint().
>
> What do you mean with "good to have"? It doesn't work without it unless
> I disable PERF_EVENTS (which is the only way to disable
> HAVE_HW_BREAKPOINT).
>
> Andreas.
>
Let me see if I can cook up a patch for this i.e. make set_dabr() invoke
register_user_hw_breakpoint() when CONFIG_PPC_BOOK3S is defined; before I
head out on my vacation (starting second week of this month).
Thanks,
K.Prasad
^ permalink raw reply
* Re: [PATCH] drivers: char: hvc: add arm JTAG DCC console support
From: Stephen Boyd @ 2010-12-01 5:30 UTC (permalink / raw)
To: Daniel Walker
Cc: Randy Dunlap, Mike Frysinger, Arnd Bergmann, Nicolas Pitre,
Tony Lindgren, linux-arm-msm, Greg Kroah-Hartman, linux-kernel,
FUJITA Tomonori, Andrew Morton, linuxppc-dev, Alan Cox
In-Reply-To: <1291145141-18301-1-git-send-email-dwalker@codeaurora.org>
On 11/30/2010 11:25 AM, Daniel Walker wrote:
> @@ -682,6 +682,15 @@ config HVC_UDBG
> select HVC_DRIVER
> default n
>
> +config HVC_DCC
> + bool "ARM JTAG DCC console"
> + depends on ARM
> + select HVC_DRIVER
> + help
> + This console uses the JTAG DCC on ARM to create a console under the HVC
Looks like you added one too many spaces for indent here.
> diff --git a/drivers/char/hvc_dcc.c b/drivers/char/hvc_dcc.c
> new file mode 100644
> index 0000000..6470f63
> --- /dev/null
> +++ b/drivers/char/hvc_dcc.c
> +static inline u32 __dcc_getstatus(void)
> +{
> + u32 __ret;
> +
> + asm("mrc p14, 0, %0, c0, c1, 0 @ read comms ctrl reg"
> + : "=r" (__ret) : : "cc");
> +
> + return __ret;
> +}
Without marking this asm volatile my compiler decides it can cache the
value of __ret in a register and then check the value of it continually
in hvc_dcc_put_chars() (I had to replace get_wait/put_wait with 1 and
fixup the branch otherwise my disassembler barfed on __dcc_(get|put)char).
00000000 <hvc_dcc_put_chars>:
0: ee103e11 mrc 14, 0, r3, cr0, cr1, {0}
4: e3a0c000 mov ip, #0 ; 0x0
8: e2033202 and r3, r3, #536870912 ; 0x20000000
c: ea000006 b 2c <hvc_dcc_put_chars+0x2c>
10: e3530000 cmp r3, #0 ; 0x0
14: 1afffffd bne 10 <hvc_dcc_put_chars+0x10>
18: e7d1000c ldrb r0, [r1, ip]
1c: ee10fe11 mrc 14, 0, pc, cr0, cr1, {0}
20: 2afffffd bcs 1c <hvc_dcc_put_chars+0x1c>
24: ee000e15 mcr 14, 0, r0, cr0, cr5, {0}
28: e28cc001 add ip, ip, #1 ; 0x1
2c: e15c0002 cmp ip, r2
30: bafffff6 blt 10 <hvc_dcc_put_chars+0x10>
34: e1a00002 mov r0, r2
38: e12fff1e bx lr
As you can see, the value of the mrc is checked against DCC_STATUS_TX
(bit 29) and then stored in r3 for later use. Marking this volatile
produces the following:
00000000 <hvc_dcc_put_chars>:
0: e3a03000 mov r3, #0 ; 0x0
4: ea000007 b 28 <hvc_dcc_put_chars+0x28>
8: ee100e11 mrc 14, 0, r0, cr0, cr1, {0}
c: e3100202 tst r0, #536870912 ; 0x20000000
10: 1afffffc bne 8 <hvc_dcc_put_chars+0x8>
14: e7d10003 ldrb r0, [r1, r3]
18: ee10fe11 mrc 14, 0, pc, cr0, cr1, {0}
1c: 2afffffd bcs 18 <hvc_dcc_put_chars+0x18>
20: ee000e15 mcr 14, 0, r0, cr0, cr5, {0}
24: e2833001 add r3, r3, #1 ; 0x1
28: e1530002 cmp r3, r2
2c: bafffff5 blt 8 <hvc_dcc_put_chars+0x8>
30: e1a00002 mov r0, r2
34: e12fff1e bx lr
which looks better.
I marked all the asm in this driver as volatile. Is that correct?
> +#if defined(CONFIG_CPU_V7)
> +static inline char __dcc_getchar(void)
> +{
> + char __c;
> +
> + asm("get_wait: mrc p14, 0, pc, c0, c1, 0 \n\
> + bne get_wait \n\
> + mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
> + : "=r" (__c) : : "cc");
> +
> + return __c;
> +}
> +#else
> +static inline char __dcc_getchar(void)
> +{
> + char __c;
> +
> + asm("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg"
> + : "=r" (__c));
> +
> + return __c;
> +}
> +#endif
> +
> +#if defined(CONFIG_CPU_V7)
> +static inline void __dcc_putchar(char c)
> +{
> + asm("put_wait: mrc p14, 0, pc, c0, c1, 0 \n\
> + bcs put_wait \n\
> + mcr p14, 0, %0, c0, c5, 0 "
> + : : "r" (c) : "cc");
> +}
> +#else
> +static inline void __dcc_putchar(char c)
> +{
> + asm("mcr p14, 0, %0, c0, c5, 0 @ write a char"
> + : /* no output register */
> + : "r" (c));
> +}
> +#endif
> +
I don't think both the v7 and v6 functions are necessary. It seems I can
get away with just the second version of __dcc_(get|put)char() on a v7.
The mrc p14, 0, pc, c0, c1, 0 will assign the top 4 bits (31-28) to the
condition codes NZCV on v7. It also looks like on an ARM11 (a v6) will
also do the same thing if I read the manuals right. The test in the
inline assembly is saying, wait for a character to be ready or wait for
a character to be read then actually write a character or read one. The
code in hvc_dcc_put_chars() is already doing the same thing, albeit in a
slightly different form. Instead of getting the status bits put into the
condition codes and looping with bne or bcs it will read the register,
and it with bit 29 or bit 28 to see if it should wait and then continue
with the writing/reading. I think you can just drop the looping for the
v7 version of the functions and have this driver work on v6 and v7.
Alternatively, you can make some function that says tx buffer is empty,
rx buffer is full or something but I don't see how saving a couple
instructions buys us much when we can have one driver for v6 and v7.
I see that Tony Lindgren modified the DCC macros for v7 in commit
200b7a8 (ARM: 5884/1: arm: Fix DCC console for v7, 2010-01-19). I'm not
sure why though, since it seems that a v6 and a v7 should really do the
same thing by waiting for the buffers to be ready before filling them or
reading them. Which probably means we can get low-level dcc debugging on
all targets if I'm not mistaken.
> +static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
> +{
> + int i;
> +
> + for (i = 0; i < count; i++) {
> + while (__dcc_getstatus() & DCC_STATUS_TX)
> + cpu_relax();
> +
> + __dcc_putchar((char)(buf[i] & 0xFF));
Is this & 0xFF and cast to char unnecessary? buf is a char array, and
chars are always 8 bits. Can't we just do __dcc_putchar(buf[i])?
> +static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
> +{
> + int i;
> +
> + for (i = 0; i < count; ++i) {
> + int c = -1;
> +
> + if (__dcc_getstatus() & DCC_STATUS_RX)
> + c = __dcc_getchar();
> + if (c < 0)
> + break;
> + buf[i] = c;
> + }
I think this for loop can be simplified. __dcc_getchar() returns a char.
It never returns -1, so the check for c < 0 can't be taken if
__dcc_getstatus() & DCC_STATUS_RX is true. The only case you break the
loop in then is if __dcc_getstatus() & DCC_STATUS_RX is false. So you
can have a simple if-else and assign buf[i] in the if branch and break
in the else branch.
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox