aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2013-11-13 04:38:27 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-11-15 08:08:40 -0500
commite657d8fe2faf49ed5d35e2325bd0f1712b8058cd (patch)
tree420f6c638e1a42f3a83135eff827dd4832544023
parentf8049e3e869f6de644e4302b3d85d06e185ddced (diff)
s390/sclp: Determine HSA size dynamically for zfcpdump
Currently we have hardcoded the HSA size to 32 MiB. With this patch the HSA size is determined dynamically via SCLP in early.c. Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/sclp.h2
-rw-r--r--arch/s390/include/asm/setup.h3
-rw-r--r--arch/s390/kernel/crash_dump.c22
-rw-r--r--arch/s390/kernel/early.c1
-rw-r--r--arch/s390/kernel/setup.c7
-rw-r--r--drivers/s390/char/Makefile3
-rw-r--r--drivers/s390/char/sclp.h1
-rw-r--r--drivers/s390/char/sclp_cmd.c2
-rw-r--r--drivers/s390/char/sclp_early.c111
-rw-r--r--drivers/s390/char/zcore.c22
10 files changed, 142 insertions, 32 deletions
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index 7dc7f9c63b65..593069201bb9 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -57,5 +57,7 @@ bool sclp_has_vt220(void);
57int sclp_pci_configure(u32 fid); 57int sclp_pci_configure(u32 fid);
58int sclp_pci_deconfigure(u32 fid); 58int sclp_pci_deconfigure(u32 fid);
59int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode); 59int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
60void sclp_hsa_size_detect(void);
61unsigned long sclp_get_hsa_size(void);
60 62
61#endif /* _ASM_S390_SCLP_H */ 63#endif /* _ASM_S390_SCLP_H */
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index df802ee14af6..94cfbe442f12 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -107,9 +107,6 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
107#define MACHINE_HAS_RRBM (S390_lowcore.machine_flags & MACHINE_FLAG_RRBM) 107#define MACHINE_HAS_RRBM (S390_lowcore.machine_flags & MACHINE_FLAG_RRBM)
108#endif /* CONFIG_64BIT */ 108#endif /* CONFIG_64BIT */
109 109
110#define ZFCPDUMP_HSA_SIZE (32UL<<20)
111#define ZFCPDUMP_HSA_SIZE_MAX (64UL<<20)
112
113/* 110/*
114 * Console mode. Override with conmode= 111 * Console mode. Override with conmode=
115 */ 112 */
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index f45b2ab0cb81..d7658c4b2ed5 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -95,7 +95,7 @@ static void *elfcorehdr_newmem;
95/* 95/*
96 * Copy one page from zfcpdump "oldmem" 96 * Copy one page from zfcpdump "oldmem"
97 * 97 *
98 * For pages below ZFCPDUMP_HSA_SIZE memory from the HSA is copied. Otherwise 98 * For pages below HSA size memory from the HSA is copied. Otherwise
99 * real memory copy is used. 99 * real memory copy is used.
100 */ 100 */
101static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize, 101static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
@@ -103,7 +103,7 @@ static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
103{ 103{
104 int rc; 104 int rc;
105 105
106 if (src < ZFCPDUMP_HSA_SIZE) { 106 if (src < sclp_get_hsa_size()) {
107 rc = memcpy_hsa(buf, src, csize, userbuf); 107 rc = memcpy_hsa(buf, src, csize, userbuf);
108 } else { 108 } else {
109 if (userbuf) 109 if (userbuf)
@@ -188,18 +188,19 @@ static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma,
188/* 188/*
189 * Remap "oldmem" for zfcpdump 189 * Remap "oldmem" for zfcpdump
190 * 190 *
191 * We only map available memory above ZFCPDUMP_HSA_SIZE. Memory below 191 * We only map available memory above HSA size. Memory below HSA size
192 * ZFCPDUMP_HSA_SIZE is read on demand using the copy_oldmem_page() function. 192 * is read on demand using the copy_oldmem_page() function.
193 */ 193 */
194static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma, 194static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma,
195 unsigned long from, 195 unsigned long from,
196 unsigned long pfn, 196 unsigned long pfn,
197 unsigned long size, pgprot_t prot) 197 unsigned long size, pgprot_t prot)
198{ 198{
199 unsigned long hsa_end = sclp_get_hsa_size();
199 unsigned long size_hsa; 200 unsigned long size_hsa;
200 201
201 if (pfn < ZFCPDUMP_HSA_SIZE >> PAGE_SHIFT) { 202 if (pfn < hsa_end >> PAGE_SHIFT) {
202 size_hsa = min(size, ZFCPDUMP_HSA_SIZE - (pfn << PAGE_SHIFT)); 203 size_hsa = min(size, hsa_end - (pfn << PAGE_SHIFT));
203 if (size == size_hsa) 204 if (size == size_hsa)
204 return 0; 205 return 0;
205 size -= size_hsa; 206 size -= size_hsa;
@@ -238,9 +239,9 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
238 return rc; 239 return rc;
239 } 240 }
240 } else { 241 } else {
241 if ((unsigned long) src < ZFCPDUMP_HSA_SIZE) { 242 unsigned long hsa_end = sclp_get_hsa_size();
242 copied = min(count, 243 if ((unsigned long) src < hsa_end) {
243 ZFCPDUMP_HSA_SIZE - (unsigned long) src); 244 copied = min(count, hsa_end - (unsigned long) src);
244 rc = memcpy_hsa(dest, (unsigned long) src, copied, 0); 245 rc = memcpy_hsa(dest, (unsigned long) src, copied, 0);
245 if (rc) 246 if (rc)
246 return rc; 247 return rc;
@@ -580,6 +581,9 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
580 /* If elfcorehdr= has been passed via cmdline, we use that one */ 581 /* If elfcorehdr= has been passed via cmdline, we use that one */
581 if (elfcorehdr_addr != ELFCORE_ADDR_MAX) 582 if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
582 return 0; 583 return 0;
584 /* If we cannot get HSA size for zfcpdump return error */
585 if (ipl_info.type == IPL_TYPE_FCP_DUMP && !sclp_get_hsa_size())
586 return -ENODEV;
583 mem_chunk_cnt = get_mem_chunk_cnt(); 587 mem_chunk_cnt = get_mem_chunk_cnt();
584 588
585 alloc_size = 0x1000 + get_cpu_cnt() * 0x300 + 589 alloc_size = 0x1000 + get_cpu_cnt() * 0x300 +
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 96543ac400a7..c0462f45cf1b 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -484,6 +484,7 @@ void __init startup_init(void)
484 detect_machine_facilities(); 484 detect_machine_facilities();
485 setup_topology(); 485 setup_topology();
486 sclp_facilities_detect(); 486 sclp_facilities_detect();
487 sclp_hsa_size_detect();
487#ifdef CONFIG_DYNAMIC_FTRACE 488#ifdef CONFIG_DYNAMIC_FTRACE
488 S390_lowcore.ftrace_func = (unsigned long)ftrace_caller; 489 S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
489#endif 490#endif
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index ffe1c53264a7..4444875266ee 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -471,8 +471,9 @@ static void __init setup_memory_end(void)
471 471
472 472
473#ifdef CONFIG_ZFCPDUMP 473#ifdef CONFIG_ZFCPDUMP
474 if (ipl_info.type == IPL_TYPE_FCP_DUMP && !OLDMEM_BASE) { 474 if (ipl_info.type == IPL_TYPE_FCP_DUMP &&
475 memory_end = ZFCPDUMP_HSA_SIZE; 475 !OLDMEM_BASE && sclp_get_hsa_size()) {
476 memory_end = sclp_get_hsa_size();
476 memory_end_set = 1; 477 memory_end_set = 1;
477 } 478 }
478#endif 479#endif
@@ -586,7 +587,7 @@ static unsigned long __init find_crash_base(unsigned long crash_size,
586 crash_base = (chunk->addr + chunk->size) - crash_size; 587 crash_base = (chunk->addr + chunk->size) - crash_size;
587 if (crash_base < crash_size) 588 if (crash_base < crash_size)
588 continue; 589 continue;
589 if (crash_base < ZFCPDUMP_HSA_SIZE_MAX) 590 if (crash_base < sclp_get_hsa_size())
590 continue; 591 continue;
591 if (crash_base < (unsigned long) INITRD_START + INITRD_SIZE) 592 if (crash_base < (unsigned long) INITRD_START + INITRD_SIZE)
592 continue; 593 continue;
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 17821a026c9c..b69ab17f13fa 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -3,7 +3,8 @@
3# 3#
4 4
5obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ 5obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
6 sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o 6 sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \
7 sclp_early.o
7 8
8obj-$(CONFIG_TN3270) += raw3270.o 9obj-$(CONFIG_TN3270) += raw3270.o
9obj-$(CONFIG_TN3270_CONSOLE) += con3270.o 10obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 40d1406289ed..9cb8076f66c4 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -172,6 +172,7 @@ int sclp_deactivate(void);
172int sclp_reactivate(void); 172int sclp_reactivate(void);
173int sclp_service_call(sclp_cmdw_t command, void *sccb); 173int sclp_service_call(sclp_cmdw_t command, void *sccb);
174int sclp_sync_request(sclp_cmdw_t command, void *sccb); 174int sclp_sync_request(sclp_cmdw_t command, void *sccb);
175int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb);
175 176
176int sclp_sdias_init(void); 177int sclp_sdias_init(void);
177void sclp_sdias_exit(void); 178void sclp_sdias_exit(void);
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 77df9cb00688..5bbe6db988b9 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -59,7 +59,7 @@ static u8 sclp_fac84;
59static unsigned long long rzm; 59static unsigned long long rzm;
60static unsigned long long rnmax; 60static unsigned long long rnmax;
61 61
62static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) 62int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
63{ 63{
64 int rc; 64 int rc;
65 65
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
new file mode 100644
index 000000000000..775112964eef
--- /dev/null
+++ b/drivers/s390/char/sclp_early.c
@@ -0,0 +1,111 @@
1/*
2 * SCLP early driver
3 *
4 * Copyright IBM Corp. 2013
5 */
6
7#define KMSG_COMPONENT "sclp_early"
8#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
9
10#include <asm/sclp.h>
11#include <asm/ipl.h>
12#include "sclp_sdias.h"
13#include "sclp.h"
14
15static __initdata char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE);
16static unsigned long sclp_hsa_size;
17
18static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb)
19{
20 int rc;
21
22 do {
23 rc = sclp_cmd_sync_early(cmd, sccb);
24 } while (rc == -EBUSY);
25
26 if (rc)
27 return -EIO;
28 if (((struct sccb_header *) sccb)->response_code != 0x0020)
29 return -EIO;
30 return 0;
31}
32
33static void __init sccb_init_eq_size(struct sdias_sccb *sccb)
34{
35 memset(sccb, 0, sizeof(*sccb));
36
37 sccb->hdr.length = sizeof(*sccb);
38 sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
39 sccb->evbuf.hdr.type = EVTYP_SDIAS;
40 sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
41 sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
42 sccb->evbuf.event_id = 4712;
43 sccb->evbuf.dbs = 1;
44}
45
46static int __init sclp_set_event_mask(unsigned long receive_mask,
47 unsigned long send_mask)
48{
49 struct init_sccb *sccb = (void *) &sccb_early;
50
51 memset(sccb, 0, sizeof(*sccb));
52 sccb->header.length = sizeof(*sccb);
53 sccb->mask_length = sizeof(sccb_mask_t);
54 sccb->receive_mask = receive_mask;
55 sccb->send_mask = send_mask;
56 return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
57}
58
59static long __init sclp_hsa_size_init(void)
60{
61 struct sdias_sccb *sccb = (void *) &sccb_early;
62
63 sccb_init_eq_size(sccb);
64 if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
65 return -EIO;
66 if (sccb->evbuf.blk_cnt != 0)
67 return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
68 return 0;
69}
70
71static long __init sclp_hsa_copy_wait(void)
72{
73 struct sccb_header *sccb = (void *) &sccb_early;
74
75 memset(sccb, 0, PAGE_SIZE);
76 sccb->length = PAGE_SIZE;
77 if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
78 return -EIO;
79 return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
80}
81
82unsigned long sclp_get_hsa_size(void)
83{
84 return sclp_hsa_size;
85}
86
87void __init sclp_hsa_size_detect(void)
88{
89 long size;
90
91 /* First try synchronous interface (LPAR) */
92 if (sclp_set_event_mask(0, 0x40000010))
93 return;
94 size = sclp_hsa_size_init();
95 if (size < 0)
96 return;
97 if (size != 0)
98 goto out;
99 /* Then try asynchronous interface (z/VM) */
100 if (sclp_set_event_mask(0x00000010, 0x40000010))
101 return;
102 size = sclp_hsa_size_init();
103 if (size < 0)
104 return;
105 size = sclp_hsa_copy_wait();
106 if (size < 0)
107 return;
108out:
109 sclp_set_event_mask(0, 0);
110 sclp_hsa_size = size;
111}
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index ffb1fcf0bf5b..3d8e4d63f514 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -328,9 +328,9 @@ static ssize_t zcore_read(struct file *file, char __user *buf, size_t count,
328 mem_offs = 0; 328 mem_offs = 0;
329 329
330 /* Copy from HSA data */ 330 /* Copy from HSA data */
331 if (*ppos < (ZFCPDUMP_HSA_SIZE + HEADER_SIZE)) { 331 if (*ppos < sclp_get_hsa_size() + HEADER_SIZE) {
332 size = min((count - hdr_count), (size_t) (ZFCPDUMP_HSA_SIZE 332 size = min((count - hdr_count),
333 - mem_start)); 333 (size_t) (sclp_get_hsa_size() - mem_start));
334 rc = memcpy_hsa_user(buf + hdr_count, mem_start, size); 334 rc = memcpy_hsa_user(buf + hdr_count, mem_start, size);
335 if (rc) 335 if (rc)
336 goto fail; 336 goto fail;
@@ -490,7 +490,7 @@ static ssize_t zcore_hsa_read(struct file *filp, char __user *buf,
490 static char str[18]; 490 static char str[18];
491 491
492 if (hsa_available) 492 if (hsa_available)
493 snprintf(str, sizeof(str), "%lx\n", ZFCPDUMP_HSA_SIZE); 493 snprintf(str, sizeof(str), "%lx\n", sclp_get_hsa_size());
494 else 494 else
495 snprintf(str, sizeof(str), "0\n"); 495 snprintf(str, sizeof(str), "0\n");
496 return simple_read_from_buffer(buf, count, ppos, str, strlen(str)); 496 return simple_read_from_buffer(buf, count, ppos, str, strlen(str));
@@ -584,17 +584,9 @@ static int __init sys_info_init(enum arch_id arch, unsigned long mem_end)
584 584
585static int __init check_sdias(void) 585static int __init check_sdias(void)
586{ 586{
587 int rc, act_hsa_size; 587 if (!sclp_get_hsa_size()) {
588
589 rc = sclp_sdias_blk_count();
590 if (rc < 0) {
591 TRACE("Could not determine HSA size\n"); 588 TRACE("Could not determine HSA size\n");
592 return rc; 589 return -ENODEV;
593 }
594 act_hsa_size = (rc - 1) * PAGE_SIZE;
595 if (act_hsa_size < ZFCPDUMP_HSA_SIZE) {
596 TRACE("HSA size too small: %i\n", act_hsa_size);
597 return -EINVAL;
598 } 590 }
599 return 0; 591 return 0;
600} 592}
@@ -662,7 +654,7 @@ static int __init zcore_reipl_init(void)
662 ipl_block = (void *) __get_free_page(GFP_KERNEL); 654 ipl_block = (void *) __get_free_page(GFP_KERNEL);
663 if (!ipl_block) 655 if (!ipl_block)
664 return -ENOMEM; 656 return -ENOMEM;
665 if (ipib_info.ipib < ZFCPDUMP_HSA_SIZE) 657 if (ipib_info.ipib < sclp_get_hsa_size())
666 rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE); 658 rc = memcpy_hsa_kernel(ipl_block, ipib_info.ipib, PAGE_SIZE);
667 else 659 else
668 rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE); 660 rc = memcpy_real(ipl_block, (void *) ipib_info.ipib, PAGE_SIZE);