xref: /kvm-unit-tests/lib/s390x/sclp.c (revision bfed1760b7c05d810a4a049dfdc4360621f84847)
1 /*
2  * s390x SCLP driver
3  *
4  * Copyright (c) 2017 Red Hat Inc
5  *
6  * Authors:
7  *  David Hildenbrand <david@redhat.com>
8  *
9  * This code is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Library General Public License version 2.
11  */
12 
13 #include <libcflat.h>
14 #include <asm/page.h>
15 #include <asm/arch_def.h>
16 #include <asm/interrupt.h>
17 #include "sclp.h"
18 #include <alloc_phys.h>
19 #include <alloc_page.h>
20 
21 extern unsigned long stacktop;
22 
23 static uint64_t storage_increment_size;
24 static uint64_t max_ram_size;
25 static uint64_t ram_size;
26 
27 char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
28 
29 static void mem_init(phys_addr_t mem_end)
30 {
31 	phys_addr_t freemem_start = (phys_addr_t)&stacktop;
32 	phys_addr_t base, top;
33 
34 	phys_alloc_init(freemem_start, mem_end - freemem_start);
35 	phys_alloc_get_unused(&base, &top);
36 	base = (base + PAGE_SIZE - 1) & -PAGE_SIZE;
37 	top = top & -PAGE_SIZE;
38 
39 	/* Make the pages available to the physical allocator */
40 	free_pages((void *)(unsigned long)base, top - base);
41 	page_alloc_ops_enable();
42 }
43 
44 static void sclp_read_scp_info(ReadInfo *ri, int length)
45 {
46 	unsigned int commands[] = { SCLP_CMDW_READ_SCP_INFO_FORCED,
47 				    SCLP_CMDW_READ_SCP_INFO };
48 	int i;
49 
50 	for (i = 0; i < ARRAY_SIZE(commands); i++) {
51 		memset(&ri->h, 0, sizeof(ri->h));
52 		ri->h.length = length;
53 
54 		if (sclp_service_call(commands[i], ri))
55 			break;
56 		if (ri->h.response_code == SCLP_RC_NORMAL_READ_COMPLETION)
57 			return;
58 		if (ri->h.response_code != SCLP_RC_INVALID_SCLP_COMMAND)
59 			break;
60 	}
61 	report_abort("READ_SCP_INFO failed");
62 }
63 
64 /* Perform service call. Return 0 on success, non-zero otherwise. */
65 int sclp_service_call(unsigned int command, void *sccb)
66 {
67 	int cc;
68 
69 	asm volatile(
70 		"       .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
71 		"       ipm     %0\n"
72 		"       srl     %0,28"
73 		: "=&d" (cc) : "d" (command), "a" (__pa(sccb))
74 		: "cc", "memory");
75 	if (cc == 3)
76 		return -1;
77 	if (cc == 2)
78 		return -1;
79 	return 0;
80 }
81 
82 void sclp_memory_setup(void)
83 {
84 	ReadInfo *ri = (void *)_sccb;
85 	uint64_t rnmax, rnsize;
86 	int cc;
87 
88 	sclp_read_scp_info(ri, SCCB_SIZE);
89 
90 	/* calculate the storage increment size */
91 	rnsize = ri->rnsize;
92 	if (!rnsize) {
93 		rnsize = ri->rnsize2;
94 	}
95 	storage_increment_size = rnsize << 20;
96 
97 	/* calculate the maximum memory size */
98 	rnmax = ri->rnmax;
99 	if (!rnmax) {
100 		rnmax = ri->rnmax2;
101 	}
102 	max_ram_size = rnmax * storage_increment_size;
103 
104 	/* lowcore is always accessible, so the first increment is accessible */
105 	ram_size = storage_increment_size;
106 
107 	/* probe for r/w memory up to max memory size */
108 	while (ram_size < max_ram_size) {
109 		expect_pgm_int();
110 		cc = tprot(ram_size + storage_increment_size - 1);
111 		/* stop once we receive an exception or have protected memory */
112 		if (clear_pgm_int() || cc != 0)
113 			break;
114 		ram_size += storage_increment_size;
115 	}
116 
117 	mem_init(ram_size);
118 }
119