提交 a9c508da 编写于 作者: M Manish Ahuja 提交者: Paul Mackerras

[POWERPC] pseries: phyp dump: Invalidate and print dump areas

This adds routines to
a. invalidate dump
b. calculate region that is reserved and needs to be freed.  This is
   exported through sysfs interface.

Unregister has been removed for now as it wasn't being used.
Signed-off-by: NManish Ahuja <mahuja@us.ibm.com>
Signed-off-by: NPaul Mackerras <paulus@samba.org>
上级 599c1aa5
...@@ -70,6 +70,10 @@ static struct phyp_dump_header phdr; ...@@ -70,6 +70,10 @@ static struct phyp_dump_header phdr;
#define DUMP_SOURCE_CPU 0x0001 #define DUMP_SOURCE_CPU 0x0001
#define DUMP_SOURCE_HPTE 0x0002 #define DUMP_SOURCE_HPTE 0x0002
#define DUMP_SOURCE_RMO 0x0011 #define DUMP_SOURCE_RMO 0x0011
#define DUMP_ERROR_FLAG 0x2000
#define DUMP_TRIGGERED 0x4000
#define DUMP_PERFORMED 0x8000
/** /**
* init_dump_header() - initialize the header declaring a dump * init_dump_header() - initialize the header declaring a dump
...@@ -181,9 +185,15 @@ static void print_dump_header(const struct phyp_dump_header *ph) ...@@ -181,9 +185,15 @@ static void print_dump_header(const struct phyp_dump_header *ph)
static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr)
{ {
int rc; int rc;
ph->cpu_data.destination_address += addr;
ph->hpte_data.destination_address += addr; /* Add addr value if not initialized before */
ph->kernel_data.destination_address += addr; if (ph->cpu_data.destination_address == 0) {
ph->cpu_data.destination_address += addr;
ph->hpte_data.destination_address += addr;
ph->kernel_data.destination_address += addr;
}
/* ToDo Invalidate kdump and free memory range. */
do { do {
rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL,
...@@ -197,6 +207,30 @@ static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) ...@@ -197,6 +207,30 @@ static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr)
} }
} }
static
void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr)
{
int rc;
/* Add addr value if not initialized before */
if (ph->cpu_data.destination_address == 0) {
ph->cpu_data.destination_address += addr;
ph->hpte_data.destination_address += addr;
ph->kernel_data.destination_address += addr;
}
do {
rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL,
2, ph, sizeof(struct phyp_dump_header));
} while (rtas_busy_delay(rc));
if (rc) {
printk(KERN_ERR "phyp-dump: unexpected error (%d) "
"on invalidate\n", rc);
print_dump_header(ph);
}
}
/* ------------------------------------------------- */ /* ------------------------------------------------- */
/** /**
* release_memory_range -- release memory previously lmb_reserved * release_memory_range -- release memory previously lmb_reserved
...@@ -207,8 +241,8 @@ static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) ...@@ -207,8 +241,8 @@ static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr)
* lmb_reserved in early boot. The released memory becomes * lmb_reserved in early boot. The released memory becomes
* available for genreal use. * available for genreal use.
*/ */
static void static void release_memory_range(unsigned long start_pfn,
release_memory_range(unsigned long start_pfn, unsigned long nr_pages) unsigned long nr_pages)
{ {
struct page *rpage; struct page *rpage;
unsigned long end_pfn; unsigned long end_pfn;
...@@ -269,8 +303,29 @@ static ssize_t store_release_region(struct kobject *kobj, ...@@ -269,8 +303,29 @@ static ssize_t store_release_region(struct kobject *kobj,
return count; return count;
} }
static ssize_t show_release_region(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
u64 second_addr_range;
/* total reserved size - start of scratch area */
second_addr_range = phyp_dump_info->init_reserve_size -
phyp_dump_info->reserved_scratch_size;
return sprintf(buf, "CPU:0x%lx-0x%lx: HPTE:0x%lx-0x%lx:"
" DUMP:0x%lx-0x%lx, 0x%lx-0x%lx:\n",
phdr.cpu_data.destination_address,
phdr.cpu_data.length_copied,
phdr.hpte_data.destination_address,
phdr.hpte_data.length_copied,
phdr.kernel_data.destination_address,
phdr.kernel_data.length_copied,
phyp_dump_info->init_reserve_start,
second_addr_range);
}
static struct kobj_attribute rr = __ATTR(release_region, 0600, static struct kobj_attribute rr = __ATTR(release_region, 0600,
NULL, store_release_region); show_release_region,
store_release_region);
static int __init phyp_dump_setup(void) static int __init phyp_dump_setup(void)
{ {
...@@ -313,6 +368,22 @@ static int __init phyp_dump_setup(void) ...@@ -313,6 +368,22 @@ static int __init phyp_dump_setup(void)
return 0; return 0;
} }
/* re-register the dump area, if old dump was invalid */
if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) {
invalidate_last_dump(&phdr, dump_area_start);
register_dump_area(&phdr, dump_area_start);
return 0;
}
if (dump_header) {
phyp_dump_info->reserved_scratch_addr =
dump_header->cpu_data.destination_address;
phyp_dump_info->reserved_scratch_size =
dump_header->cpu_data.source_length +
dump_header->hpte_data.source_length +
dump_header->kernel_data.source_length;
}
/* Should we create a dump_subsys, analogous to s390/ipl.c ? */ /* Should we create a dump_subsys, analogous to s390/ipl.c ? */
rc = sysfs_create_file(kernel_kobj, &rr.attr); rc = sysfs_create_file(kernel_kobj, &rr.attr);
if (rc) if (rc)
......
...@@ -30,6 +30,9 @@ struct phyp_dump { ...@@ -30,6 +30,9 @@ struct phyp_dump {
/* store cpu & hpte size */ /* store cpu & hpte size */
unsigned long cpu_state_size; unsigned long cpu_state_size;
unsigned long hpte_region_size; unsigned long hpte_region_size;
/* previous scratch area values */
unsigned long reserved_scratch_addr;
unsigned long reserved_scratch_size;
}; };
extern struct phyp_dump *phyp_dump_info; extern struct phyp_dump *phyp_dump_info;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册