Commit 6f79d332 authored by Michael Holzheu's avatar Michael Holzheu Committed by Linus Torvalds

s390/vmcore: use vmcore for zfcpdump

Modify the s390 copy_oldmem_page() and remap_oldmem_pfn_range() function
for zfcpdump to read from the HSA memory if memory below HSA_SIZE bytes is
requested.  Otherwise real memory is used.
Signed-off-by: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: Jan Willeke <willeke@de.ibm.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 11e376a3
...@@ -526,6 +526,7 @@ config CRASH_DUMP ...@@ -526,6 +526,7 @@ config CRASH_DUMP
bool "kernel crash dumps" bool "kernel crash dumps"
depends on 64BIT && SMP depends on 64BIT && SMP
select KEXEC select KEXEC
select ZFCPDUMP
help help
Generate crash dump after being started by kexec. Generate crash dump after being started by kexec.
Crash dump kernels are loaded in the main kernel with kexec-tools Crash dump kernels are loaded in the main kernel with kexec-tools
...@@ -536,7 +537,7 @@ config CRASH_DUMP ...@@ -536,7 +537,7 @@ config CRASH_DUMP
config ZFCPDUMP config ZFCPDUMP
def_bool n def_bool n
prompt "zfcpdump support" prompt "zfcpdump support"
select SMP depends on SMP
help help
Select this option if you want to build an zfcpdump enabled kernel. Select this option if you want to build an zfcpdump enabled kernel.
Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this. Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
......
...@@ -56,5 +56,6 @@ bool sclp_has_linemode(void); ...@@ -56,5 +56,6 @@ bool sclp_has_linemode(void);
bool sclp_has_vt220(void); bool sclp_has_vt220(void);
int sclp_pci_configure(u32 fid); int sclp_pci_configure(u32 fid);
int sclp_pci_deconfigure(u32 fid); int sclp_pci_deconfigure(u32 fid);
int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
#endif /* _ASM_S390_SCLP_H */ #endif /* _ASM_S390_SCLP_H */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <asm/os_info.h> #include <asm/os_info.h>
#include <asm/elf.h> #include <asm/elf.h>
#include <asm/ipl.h> #include <asm/ipl.h>
#include <asm/sclp.h>
#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
...@@ -69,22 +70,41 @@ static ssize_t copy_page_real(void *buf, void *src, size_t csize) ...@@ -69,22 +70,41 @@ static ssize_t copy_page_real(void *buf, void *src, size_t csize)
static void *elfcorehdr_newmem; static void *elfcorehdr_newmem;
/* /*
* Copy one page from "oldmem" * Copy one page from zfcpdump "oldmem"
*
* For pages below ZFCPDUMP_HSA_SIZE memory from the HSA is copied. Otherwise
* real memory copy is used.
*/
static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
unsigned long src, int userbuf)
{
int rc;
if (src < ZFCPDUMP_HSA_SIZE) {
rc = memcpy_hsa(buf, src, csize, userbuf);
} else {
if (userbuf)
rc = copy_to_user_real((void __force __user *) buf,
(void *) src, csize);
else
rc = memcpy_real(buf, (void *) src, csize);
}
return rc ? rc : csize;
}
/*
* Copy one page from kdump "oldmem"
* *
* For the kdump reserved memory this functions performs a swap operation: * For the kdump reserved memory this functions performs a swap operation:
* - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE]. * - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
* - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] * - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
*/ */
ssize_t copy_oldmem_page(unsigned long pfn, char *buf, static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
size_t csize, unsigned long offset, int userbuf) unsigned long src, int userbuf)
{ {
unsigned long src;
int rc; int rc;
if (!csize)
return 0;
src = (pfn << PAGE_SHIFT) + offset;
if (src < OLDMEM_SIZE) if (src < OLDMEM_SIZE)
src += OLDMEM_BASE; src += OLDMEM_BASE;
else if (src > OLDMEM_BASE && else if (src > OLDMEM_BASE &&
...@@ -95,17 +115,35 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, ...@@ -95,17 +115,35 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
(void *) src, csize); (void *) src, csize);
else else
rc = copy_page_real(buf, (void *) src, csize); rc = copy_page_real(buf, (void *) src, csize);
return (rc == 0) ? csize : rc; return (rc == 0) ? rc : csize;
}
/*
* Copy one page from "oldmem"
*/
ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
unsigned long offset, int userbuf)
{
unsigned long src;
if (!csize)
return 0;
src = (pfn << PAGE_SHIFT) + offset;
if (OLDMEM_BASE)
return copy_oldmem_page_kdump(buf, csize, src, userbuf);
else
return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf);
} }
/* /*
* Remap "oldmem" * Remap "oldmem" for kdump
* *
* For the kdump reserved memory this functions performs a swap operation: * For the kdump reserved memory this functions performs a swap operation:
* [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
*/ */
int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma,
unsigned long pfn, unsigned long size, pgprot_t prot) unsigned long from, unsigned long pfn,
unsigned long size, pgprot_t prot)
{ {
unsigned long size_old; unsigned long size_old;
int rc; int rc;
...@@ -124,6 +162,43 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from, ...@@ -124,6 +162,43 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
return remap_pfn_range(vma, from, pfn, size, prot); return remap_pfn_range(vma, from, pfn, size, prot);
} }
/*
* Remap "oldmem" for zfcpdump
*
* We only map available memory above ZFCPDUMP_HSA_SIZE. Memory below
* ZFCPDUMP_HSA_SIZE is read on demand using the copy_oldmem_page() function.
*/
static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma,
unsigned long from,
unsigned long pfn,
unsigned long size, pgprot_t prot)
{
unsigned long size_hsa;
if (pfn < ZFCPDUMP_HSA_SIZE >> PAGE_SHIFT) {
size_hsa = min(size, ZFCPDUMP_HSA_SIZE - (pfn << PAGE_SHIFT));
if (size == size_hsa)
return 0;
size -= size_hsa;
from += size_hsa;
pfn += size_hsa >> PAGE_SHIFT;
}
return remap_pfn_range(vma, from, pfn, size, prot);
}
/*
* Remap "oldmem" for kdump or zfcpdump
*/
int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
if (OLDMEM_BASE)
return remap_oldmem_pfn_range_kdump(vma, from, pfn, size, prot);
else
return remap_oldmem_pfn_range_zfcpdump(vma, from, pfn, size,
prot);
}
/* /*
* Copy memory from old kernel * Copy memory from old kernel
*/ */
...@@ -132,12 +207,22 @@ int copy_from_oldmem(void *dest, void *src, size_t count) ...@@ -132,12 +207,22 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
unsigned long copied = 0; unsigned long copied = 0;
int rc; int rc;
if (OLDMEM_BASE) {
if ((unsigned long) src < OLDMEM_SIZE) { if ((unsigned long) src < OLDMEM_SIZE) {
copied = min(count, OLDMEM_SIZE - (unsigned long) src); copied = min(count, OLDMEM_SIZE - (unsigned long) src);
rc = memcpy_real(dest, src + OLDMEM_BASE, copied); rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
if (rc) if (rc)
return rc; return rc;
} }
} else {
if ((unsigned long) src < ZFCPDUMP_HSA_SIZE) {
copied = min(count,
ZFCPDUMP_HSA_SIZE - (unsigned long) src);
rc = memcpy_hsa(dest, (unsigned long) src, copied, 0);
if (rc)
return rc;
}
}
return memcpy_real(dest + copied, src + copied, count - copied); return memcpy_real(dest + copied, src + copied, count - copied);
} }
...@@ -466,7 +551,8 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size) ...@@ -466,7 +551,8 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
u32 alloc_size; u32 alloc_size;
u64 hdr_off; u64 hdr_off;
if (!OLDMEM_BASE) /* If we are not in kdump or zfcpdump mode return */
if (!OLDMEM_BASE && ipl_info.type != IPL_TYPE_FCP_DUMP)
return 0; return 0;
/* If elfcorehdr= has been passed via cmdline, we use that one */ /* If elfcorehdr= has been passed via cmdline, we use that one */
if (elfcorehdr_addr != ELFCORE_ADDR_MAX) if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
......
...@@ -30,8 +30,8 @@ ...@@ -30,8 +30,8 @@
#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
#define TO_USER 0 #define TO_USER 1
#define TO_KERNEL 1 #define TO_KERNEL 0
#define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */ #define CHUNK_INFO_SIZE 34 /* 2 16-byte char, each followed by blank */
enum arch_id { enum arch_id {
...@@ -73,7 +73,7 @@ static struct ipl_parameter_block *ipl_block; ...@@ -73,7 +73,7 @@ static struct ipl_parameter_block *ipl_block;
* @count: Size of buffer, which should be copied * @count: Size of buffer, which should be copied
* @mode: Either TO_KERNEL or TO_USER * @mode: Either TO_KERNEL or TO_USER
*/ */
static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode) int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
{ {
int offs, blk_num; int offs, blk_num;
static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment