xref: /kvm-unit-tests/lib/s390x/sclp.c (revision b356c913b2c338d62b56a2e8c4a7c0f7212d9e6b)
13db880b6SDavid Hildenbrand /*
23db880b6SDavid Hildenbrand  * s390x SCLP driver
33db880b6SDavid Hildenbrand  *
43db880b6SDavid Hildenbrand  * Copyright (c) 2017 Red Hat Inc
53db880b6SDavid Hildenbrand  *
63db880b6SDavid Hildenbrand  * Authors:
73db880b6SDavid Hildenbrand  *  David Hildenbrand <david@redhat.com>
83db880b6SDavid Hildenbrand  *
93db880b6SDavid Hildenbrand  * This code is free software; you can redistribute it and/or modify it
103db880b6SDavid Hildenbrand  * under the terms of the GNU Library General Public License version 2.
113db880b6SDavid Hildenbrand  */
123db880b6SDavid Hildenbrand 
133db880b6SDavid Hildenbrand #include <libcflat.h>
143db880b6SDavid Hildenbrand #include <asm/page.h>
153db880b6SDavid Hildenbrand #include <asm/arch_def.h>
163db880b6SDavid Hildenbrand #include <asm/interrupt.h>
173db880b6SDavid Hildenbrand #include "sclp.h"
1892bbd322SDavid Hildenbrand #include <alloc_phys.h>
19*b356c913SJanosch Frank #include <alloc_page.h>
2092bbd322SDavid Hildenbrand 
2192bbd322SDavid Hildenbrand extern unsigned long stacktop;
223db880b6SDavid Hildenbrand 
233db880b6SDavid Hildenbrand static uint64_t storage_increment_size;
243db880b6SDavid Hildenbrand static uint64_t max_ram_size;
253db880b6SDavid Hildenbrand static uint64_t ram_size;
263db880b6SDavid Hildenbrand 
2735bfd1c4SJanosch Frank char _sccb[PAGE_SIZE] __attribute__((__aligned__(4096)));
2835bfd1c4SJanosch Frank 
2992bbd322SDavid Hildenbrand static void mem_init(phys_addr_t mem_end)
3092bbd322SDavid Hildenbrand {
3192bbd322SDavid Hildenbrand 	phys_addr_t freemem_start = (phys_addr_t)&stacktop;
32*b356c913SJanosch Frank 	phys_addr_t base, top;
3392bbd322SDavid Hildenbrand 
3492bbd322SDavid Hildenbrand 	phys_alloc_init(freemem_start, mem_end - freemem_start);
35*b356c913SJanosch Frank 	phys_alloc_get_unused(&base, &top);
36*b356c913SJanosch Frank 	base = (base + PAGE_SIZE - 1) & -PAGE_SIZE;
37*b356c913SJanosch Frank 	top = top & -PAGE_SIZE;
38*b356c913SJanosch Frank 
39*b356c913SJanosch Frank 	/* Make the pages available to the physical allocator */
40*b356c913SJanosch Frank 	free_pages((void *)(unsigned long)base, top - base);
41*b356c913SJanosch Frank 	page_alloc_ops_enable();
4292bbd322SDavid Hildenbrand }
4392bbd322SDavid Hildenbrand 
44a45cb177SDavid Hildenbrand static void sclp_read_scp_info(ReadInfo *ri, int length)
45a45cb177SDavid Hildenbrand {
46a45cb177SDavid Hildenbrand 	unsigned int commands[] = { SCLP_CMDW_READ_SCP_INFO_FORCED,
47a45cb177SDavid Hildenbrand 				    SCLP_CMDW_READ_SCP_INFO };
48a45cb177SDavid Hildenbrand 	int i;
49a45cb177SDavid Hildenbrand 
50a45cb177SDavid Hildenbrand 	for (i = 0; i < ARRAY_SIZE(commands); i++) {
51a45cb177SDavid Hildenbrand 		memset(&ri->h, 0, sizeof(ri->h));
52a45cb177SDavid Hildenbrand 		ri->h.length = length;
53a45cb177SDavid Hildenbrand 
54a45cb177SDavid Hildenbrand 		if (sclp_service_call(commands[i], ri))
55a45cb177SDavid Hildenbrand 			break;
56a45cb177SDavid Hildenbrand 		if (ri->h.response_code == SCLP_RC_NORMAL_READ_COMPLETION)
57a45cb177SDavid Hildenbrand 			return;
58a45cb177SDavid Hildenbrand 		if (ri->h.response_code != SCLP_RC_INVALID_SCLP_COMMAND)
59a45cb177SDavid Hildenbrand 			break;
60a45cb177SDavid Hildenbrand 	}
61a45cb177SDavid Hildenbrand 	report_abort("READ_SCP_INFO failed");
62a45cb177SDavid Hildenbrand }
63a45cb177SDavid Hildenbrand 
6435bfd1c4SJanosch Frank /* Perform service call. Return 0 on success, non-zero otherwise. */
6535bfd1c4SJanosch Frank int sclp_service_call(unsigned int command, void *sccb)
6635bfd1c4SJanosch Frank {
6735bfd1c4SJanosch Frank 	int cc;
6835bfd1c4SJanosch Frank 
6935bfd1c4SJanosch Frank 	asm volatile(
7035bfd1c4SJanosch Frank 		"       .insn   rre,0xb2200000,%1,%2\n"  /* servc %1,%2 */
7135bfd1c4SJanosch Frank 		"       ipm     %0\n"
7235bfd1c4SJanosch Frank 		"       srl     %0,28"
7335bfd1c4SJanosch Frank 		: "=&d" (cc) : "d" (command), "a" (__pa(sccb))
7435bfd1c4SJanosch Frank 		: "cc", "memory");
7535bfd1c4SJanosch Frank 	if (cc == 3)
7635bfd1c4SJanosch Frank 		return -1;
7735bfd1c4SJanosch Frank 	if (cc == 2)
7835bfd1c4SJanosch Frank 		return -1;
7935bfd1c4SJanosch Frank 	return 0;
8035bfd1c4SJanosch Frank }
8135bfd1c4SJanosch Frank 
823db880b6SDavid Hildenbrand void sclp_memory_setup(void)
833db880b6SDavid Hildenbrand {
843db880b6SDavid Hildenbrand 	ReadInfo *ri = (void *)_sccb;
853db880b6SDavid Hildenbrand 	uint64_t rnmax, rnsize;
863db880b6SDavid Hildenbrand 	int cc;
873db880b6SDavid Hildenbrand 
88a45cb177SDavid Hildenbrand 	sclp_read_scp_info(ri, SCCB_SIZE);
893db880b6SDavid Hildenbrand 
903db880b6SDavid Hildenbrand 	/* calculate the storage increment size */
913db880b6SDavid Hildenbrand 	rnsize = ri->rnsize;
923db880b6SDavid Hildenbrand 	if (!rnsize) {
933db880b6SDavid Hildenbrand 		rnsize = ri->rnsize2;
943db880b6SDavid Hildenbrand 	}
953db880b6SDavid Hildenbrand 	storage_increment_size = rnsize << 20;
963db880b6SDavid Hildenbrand 
973db880b6SDavid Hildenbrand 	/* calculate the maximum memory size */
983db880b6SDavid Hildenbrand 	rnmax = ri->rnmax;
993db880b6SDavid Hildenbrand 	if (!rnmax) {
1003db880b6SDavid Hildenbrand 		rnmax = ri->rnmax2;
1013db880b6SDavid Hildenbrand 	}
1023db880b6SDavid Hildenbrand 	max_ram_size = rnmax * storage_increment_size;
1033db880b6SDavid Hildenbrand 
1043db880b6SDavid Hildenbrand 	/* lowcore is always accessible, so the first increment is accessible */
1053db880b6SDavid Hildenbrand 	ram_size = storage_increment_size;
1063db880b6SDavid Hildenbrand 
1073db880b6SDavid Hildenbrand 	/* probe for r/w memory up to max memory size */
1083db880b6SDavid Hildenbrand 	while (ram_size < max_ram_size) {
1093db880b6SDavid Hildenbrand 		expect_pgm_int();
1103db880b6SDavid Hildenbrand 		cc = tprot(ram_size + storage_increment_size - 1);
1113db880b6SDavid Hildenbrand 		/* stop once we receive an exception or have protected memory */
1123db880b6SDavid Hildenbrand 		if (clear_pgm_int() || cc != 0)
1133db880b6SDavid Hildenbrand 			break;
1143db880b6SDavid Hildenbrand 		ram_size += storage_increment_size;
1153db880b6SDavid Hildenbrand 	}
11692bbd322SDavid Hildenbrand 
11792bbd322SDavid Hildenbrand 	mem_init(ram_size);
1183db880b6SDavid Hildenbrand }
119