powerpc/fadump: add helper functions

Add helper functions to setup & free CPU notes buffer and to find if a
given memory area is contiguous. Also, use boolean as return type for
the function that finds if boot memory area is contiguous. While at
it, save the virtual address of CPU notes buffer instead of physical
address as virtual address is used often.

Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/156821318971.5656.9281936950510635858.stgit@hbathini.in.ibm.com
This commit is contained in:
Hari Bathini 2019-09-11 20:16:36 +05:30 committed by Michael Ellerman
parent ca986d7fa7
commit 961cf26a98
2 changed files with 67 additions and 62 deletions

View File

@ -71,7 +71,7 @@ struct fw_dump {
unsigned long boot_memory_size;
unsigned long fadumphdr_addr;
unsigned long cpu_notes_buf;
unsigned long cpu_notes_buf_vaddr;
unsigned long cpu_notes_buf_size;
int ibm_configure_kernel_dump;

View File

@ -201,64 +201,55 @@ int is_fadump_active(void)
}
/*
* Returns 1, if there are no holes in boot memory area,
* 0 otherwise.
* Returns true, if there are no holes in memory area between d_start to d_end,
* false otherwise.
*/
static int is_boot_memory_area_contiguous(void)
static bool is_fadump_mem_area_contiguous(u64 d_start, u64 d_end)
{
struct memblock_region *reg;
unsigned long tstart, tend;
unsigned long start_pfn = PHYS_PFN(RMA_START);
unsigned long end_pfn = PHYS_PFN(RMA_START + fw_dump.boot_memory_size);
unsigned int ret = 0;
bool ret = false;
u64 start, end;
for_each_memblock(memory, reg) {
tstart = max(start_pfn, memblock_region_memory_base_pfn(reg));
tend = min(end_pfn, memblock_region_memory_end_pfn(reg));
if (tstart < tend) {
/* Memory hole from start_pfn to tstart */
if (tstart > start_pfn)
start = max_t(u64, d_start, reg->base);
end = min_t(u64, d_end, (reg->base + reg->size));
if (d_start < end) {
/* Memory hole from d_start to start */
if (start > d_start)
break;
if (tend == end_pfn) {
ret = 1;
if (end == d_end) {
ret = true;
break;
}
start_pfn = tend + 1;
d_start = end + 1;
}
}
return ret;
}
/*
* Returns true, if there are no holes in boot memory area,
* false otherwise.
*/
static bool is_boot_memory_area_contiguous(void)
{
return is_fadump_mem_area_contiguous(0, fw_dump.boot_memory_size);
}
/*
* Returns true, if there are no holes in reserved memory area,
* false otherwise.
*/
static bool is_reserved_memory_area_contiguous(void)
{
struct memblock_region *reg;
unsigned long start, end;
unsigned long d_start = fw_dump.reserve_dump_area_start;
unsigned long d_end = d_start + fw_dump.reserve_dump_area_size;
u64 d_start, d_end;
for_each_memblock(memory, reg) {
start = max(d_start, (unsigned long)reg->base);
end = min(d_end, (unsigned long)(reg->base + reg->size));
if (d_start < end) {
/* Memory hole from d_start to start */
if (start > d_start)
break;
if (end == d_end)
return true;
d_start = end + 1;
}
}
return false;
d_start = fw_dump.reserve_dump_area_start;
d_end = d_start + fw_dump.reserve_dump_area_size;
return is_fadump_mem_area_contiguous(d_start, d_end);
}
/* Print firmware assisted dump configurations for debugging purpose. */
@ -785,7 +776,7 @@ static void fadump_update_elfcore_header(char *bufp)
phdr = (struct elf_phdr *)bufp;
if (phdr->p_type == PT_NOTE) {
phdr->p_paddr = fw_dump.cpu_notes_buf;
phdr->p_paddr = __pa(fw_dump.cpu_notes_buf_vaddr);
phdr->p_offset = phdr->p_paddr;
phdr->p_filesz = fw_dump.cpu_notes_buf_size;
phdr->p_memsz = fw_dump.cpu_notes_buf_size;
@ -793,7 +784,7 @@ static void fadump_update_elfcore_header(char *bufp)
return;
}
static void *fadump_cpu_notes_buf_alloc(unsigned long size)
static void *fadump_alloc_buffer(unsigned long size)
{
void *vaddr;
struct page *page;
@ -811,7 +802,7 @@ static void *fadump_cpu_notes_buf_alloc(unsigned long size)
return vaddr;
}
static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size)
static void fadump_free_buffer(unsigned long vaddr, unsigned long size)
{
struct page *page;
unsigned long order, count, i;
@ -824,6 +815,36 @@ static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size)
__free_pages(page, order);
}
static s32 fadump_setup_cpu_notes_buf(u32 num_cpus)
{
/* Allocate buffer to hold cpu crash notes. */
fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
fw_dump.cpu_notes_buf_vaddr =
(unsigned long)fadump_alloc_buffer(fw_dump.cpu_notes_buf_size);
if (!fw_dump.cpu_notes_buf_vaddr) {
pr_err("Failed to allocate %ld bytes for CPU notes buffer\n",
fw_dump.cpu_notes_buf_size);
return -ENOMEM;
}
pr_debug("Allocated buffer for cpu notes of size %ld at 0x%lx\n",
fw_dump.cpu_notes_buf_size,
fw_dump.cpu_notes_buf_vaddr);
return 0;
}
static void fadump_free_cpu_notes_buf(void)
{
if (!fw_dump.cpu_notes_buf_vaddr)
return;
fadump_free_buffer(fw_dump.cpu_notes_buf_vaddr,
fw_dump.cpu_notes_buf_size);
fw_dump.cpu_notes_buf_vaddr = 0;
fw_dump.cpu_notes_buf_size = 0;
}
/*
* Read CPU state dump data and convert it into ELF notes.
* The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be
@ -870,19 +891,11 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
vaddr += sizeof(u32);
reg_entry = (struct fadump_reg_entry *)vaddr;
/* Allocate buffer to hold cpu crash notes. */
fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t);
fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size);
note_buf = fadump_cpu_notes_buf_alloc(fw_dump.cpu_notes_buf_size);
if (!note_buf) {
printk(KERN_ERR "Failed to allocate 0x%lx bytes for "
"cpu notes buffer\n", fw_dump.cpu_notes_buf_size);
return -ENOMEM;
}
fw_dump.cpu_notes_buf = __pa(note_buf);
rc = fadump_setup_cpu_notes_buf(num_cpus);
if (rc != 0)
return rc;
pr_debug("Allocated buffer for cpu notes of size %ld at %p\n",
(num_cpus * sizeof(note_buf_t)), note_buf);
note_buf = (u32 *)fw_dump.cpu_notes_buf_vaddr;
if (fw_dump.fadumphdr_addr)
fdh = __va(fw_dump.fadumphdr_addr);
@ -920,10 +933,7 @@ static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm)
return 0;
error_out:
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;
fadump_free_cpu_notes_buf();
return rc;
}
@ -1470,13 +1480,8 @@ static void fadump_invalidate_release_mem(void)
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;
}
fadump_free_cpu_notes_buf();
/* Initialize the kernel dump memory structure for FAD registration. */
init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
}