Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 292472
b: refs/heads/master
c: b500aff
h: refs/heads/master
v: v3
  • Loading branch information
Mahesh Salgaonkar authored and Benjamin Herrenschmidt committed Feb 22, 2012
1 parent f1eaf2d commit 4b1edd1
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 5 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 162573937679ff36c9acd54268c047199dab564e
refs/heads/master: b500afff11f64227ca69fd2d05986d08d9573935
3 changes: 3 additions & 0 deletions trunk/arch/powerpc/include/asm/fadump.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ extern int fadump_reserve_mem(void);
extern int setup_fadump(void);
extern int is_fadump_active(void);
extern void crash_fadump(struct pt_regs *, const char *);
extern void fadump_cleanup(void);

extern void vmcore_cleanup(void);
#else /* CONFIG_FA_DUMP */
static inline int is_fadump_active(void) { return 0; }
static inline void crash_fadump(struct pt_regs *regs, const char *str) { }
Expand Down
158 changes: 154 additions & 4 deletions trunk/arch/powerpc/kernel/fadump.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/crash_dump.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>

#include <asm/page.h>
#include <asm/prom.h>
Expand Down Expand Up @@ -984,6 +986,132 @@ static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
return 0;
}

static int fadump_invalidate_dump(struct fadump_mem_struct *fdm)
{
int rc = 0;
unsigned int wait_time;

pr_debug("Invalidating firmware-assisted dump registration\n");

/* TODO: Add upper time limit for the delay */
do {
rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
FADUMP_INVALIDATE, fdm,
sizeof(struct fadump_mem_struct));

wait_time = rtas_busy_delay_time(rc);
if (wait_time)
mdelay(wait_time);
} while (wait_time);

if (rc) {
printk(KERN_ERR "Failed to invalidate firmware-assisted dump "
"rgistration. unexpected error(%d).\n", rc);
return rc;
}
fw_dump.dump_active = 0;
fdm_active = NULL;
return 0;
}

void fadump_cleanup(void)
{
/* Invalidate the registration only if dump is active. */
if (fw_dump.dump_active) {
init_fadump_mem_struct(&fdm,
fdm_active->cpu_state_data.destination_address);
fadump_invalidate_dump(&fdm);
}
}

/*
* Release the memory that was reserved in early boot to preserve the memory
* contents. The released memory will be available for general use.
*/
static void fadump_release_memory(unsigned long begin, unsigned long end)
{
unsigned long addr;
unsigned long ra_start, ra_end;

ra_start = fw_dump.reserve_dump_area_start;
ra_end = ra_start + fw_dump.reserve_dump_area_size;

for (addr = begin; addr < end; addr += PAGE_SIZE) {
/*
* exclude the dump reserve area. Will reuse it for next
* fadump registration.
*/
if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
continue;

ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
free_page((unsigned long)__va(addr));
totalram_pages++;
}
}

static void fadump_invalidate_release_mem(void)
{
unsigned long reserved_area_start, reserved_area_end;
unsigned long destination_address;

mutex_lock(&fadump_mutex);
if (!fw_dump.dump_active) {
mutex_unlock(&fadump_mutex);
return;
}

destination_address = fdm_active->cpu_state_data.destination_address;
fadump_cleanup();
mutex_unlock(&fadump_mutex);

/*
* Save the current reserved memory bounds we will require them
* later for releasing the memory for general use.
*/
reserved_area_start = fw_dump.reserve_dump_area_start;
reserved_area_end = reserved_area_start +
fw_dump.reserve_dump_area_size;
/*
* Setup reserve_dump_area_start and its size so that we can
* reuse this reserved memory for Re-registration.
*/
fw_dump.reserve_dump_area_start = destination_address;
fw_dump.reserve_dump_area_size = get_fadump_area_size();

fadump_release_memory(reserved_area_start, reserved_area_end);
if (fw_dump.cpu_notes_buf) {
fadump_cpu_notes_buf_free(
(unsigned long)__va(fw_dump.cpu_notes_buf),
fw_dump.cpu_notes_buf_size);
fw_dump.cpu_notes_buf = 0;
fw_dump.cpu_notes_buf_size = 0;
}
/* Initialize the kernel dump memory structure for FAD registration. */
init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
}

static ssize_t fadump_release_memory_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
if (!fw_dump.dump_active)
return -EPERM;

if (buf[0] == '1') {
/*
* Take away the '/proc/vmcore'. We are releasing the dump
* memory, hence it will not be valid anymore.
*/
vmcore_cleanup();
fadump_invalidate_release_mem();

} else
return -EINVAL;
return count;
}

static ssize_t fadump_enabled_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
Expand Down Expand Up @@ -1043,10 +1171,13 @@ static int fadump_region_show(struct seq_file *m, void *private)
if (!fw_dump.fadump_enabled)
return 0;

mutex_lock(&fadump_mutex);
if (fdm_active)
fdm_ptr = fdm_active;
else
else {
mutex_unlock(&fadump_mutex);
fdm_ptr = &fdm;
}

seq_printf(m,
"CPU : [%#016llx-%#016llx] %#llx bytes, "
Expand Down Expand Up @@ -1076,7 +1207,7 @@ static int fadump_region_show(struct seq_file *m, void *private)
if (!fdm_active ||
(fw_dump.reserve_dump_area_start ==
fdm_ptr->cpu_state_data.destination_address))
return 0;
goto out;

/* Dump is active. Show reserved memory region. */
seq_printf(m,
Expand All @@ -1088,9 +1219,15 @@ static int fadump_region_show(struct seq_file *m, void *private)
fw_dump.reserve_dump_area_start,
fdm_ptr->cpu_state_data.destination_address -
fw_dump.reserve_dump_area_start);
out:
if (fdm_active)
mutex_unlock(&fadump_mutex);
return 0;
}

static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
0200, NULL,
fadump_release_memory_store);
static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
0444, fadump_enabled_show,
NULL);
Expand Down Expand Up @@ -1131,6 +1268,13 @@ static void fadump_init_files(void)
if (!debugfs_file)
printk(KERN_ERR "fadump: unable to create debugfs file"
" fadump_region\n");

if (fw_dump.dump_active) {
rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
if (rc)
printk(KERN_ERR "fadump: unable to create sysfs file"
" fadump_release_mem (%d)\n", rc);
}
return;
}

Expand All @@ -1153,8 +1297,14 @@ int __init setup_fadump(void)
* If dump data is available then see if it is valid and prepare for
* saving it to the disk.
*/
if (fw_dump.dump_active)
process_fadump(fdm_active);
if (fw_dump.dump_active) {
/*
* if dump process fails then invalidate the registration
* and release memory before proceeding for re-registration.
*/
if (process_fadump(fdm_active) < 0)
fadump_invalidate_release_mem();
}
/* Initialize the kernel dump memory structure for FAD registration. */
else if (fw_dump.reserve_dump_area_size)
init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
Expand Down

0 comments on commit 4b1edd1

Please sign in to comment.