xref: /kvm-unit-tests/lib/s390x/sclp.c (revision a45cb177325e58bc2e9f3a3442d649b28c2d9403)
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>
1992bbd322SDavid Hildenbrand 
2092bbd322SDavid Hildenbrand extern unsigned long stacktop;
213db880b6SDavid Hildenbrand 
223db880b6SDavid Hildenbrand static uint64_t storage_increment_size;
233db880b6SDavid Hildenbrand static uint64_t max_ram_size;
243db880b6SDavid Hildenbrand static uint64_t ram_size;
253db880b6SDavid Hildenbrand 
2692bbd322SDavid Hildenbrand static void mem_init(phys_addr_t mem_end)
2792bbd322SDavid Hildenbrand {
2892bbd322SDavid Hildenbrand 	phys_addr_t freemem_start = (phys_addr_t)&stacktop;
2992bbd322SDavid Hildenbrand 
3092bbd322SDavid Hildenbrand 	phys_alloc_init(freemem_start, mem_end - freemem_start);
3192bbd322SDavid Hildenbrand }
3292bbd322SDavid Hildenbrand 
33*a45cb177SDavid Hildenbrand static void sclp_read_scp_info(ReadInfo *ri, int length)
34*a45cb177SDavid Hildenbrand {
35*a45cb177SDavid Hildenbrand 	unsigned int commands[] = { SCLP_CMDW_READ_SCP_INFO_FORCED,
36*a45cb177SDavid Hildenbrand 				    SCLP_CMDW_READ_SCP_INFO };
37*a45cb177SDavid Hildenbrand 	int i;
38*a45cb177SDavid Hildenbrand 
39*a45cb177SDavid Hildenbrand 	for (i = 0; i < ARRAY_SIZE(commands); i++) {
40*a45cb177SDavid Hildenbrand 		memset(&ri->h, 0, sizeof(ri->h));
41*a45cb177SDavid Hildenbrand 		ri->h.length = length;
42*a45cb177SDavid Hildenbrand 
43*a45cb177SDavid Hildenbrand 		if (sclp_service_call(commands[i], ri))
44*a45cb177SDavid Hildenbrand 			break;
45*a45cb177SDavid Hildenbrand 		if (ri->h.response_code == SCLP_RC_NORMAL_READ_COMPLETION)
46*a45cb177SDavid Hildenbrand 			return;
47*a45cb177SDavid Hildenbrand 		if (ri->h.response_code != SCLP_RC_INVALID_SCLP_COMMAND)
48*a45cb177SDavid Hildenbrand 			break;
49*a45cb177SDavid Hildenbrand 	}
50*a45cb177SDavid Hildenbrand 	report_abort("READ_SCP_INFO failed");
51*a45cb177SDavid Hildenbrand }
52*a45cb177SDavid Hildenbrand 
533db880b6SDavid Hildenbrand void sclp_memory_setup(void)
543db880b6SDavid Hildenbrand {
553db880b6SDavid Hildenbrand 	ReadInfo *ri = (void *)_sccb;
563db880b6SDavid Hildenbrand 	uint64_t rnmax, rnsize;
573db880b6SDavid Hildenbrand 	int cc;
583db880b6SDavid Hildenbrand 
59*a45cb177SDavid Hildenbrand 	sclp_read_scp_info(ri, SCCB_SIZE);
603db880b6SDavid Hildenbrand 
613db880b6SDavid Hildenbrand 	/* calculate the storage increment size */
623db880b6SDavid Hildenbrand 	rnsize = ri->rnsize;
633db880b6SDavid Hildenbrand 	if (!rnsize) {
643db880b6SDavid Hildenbrand 		rnsize = ri->rnsize2;
653db880b6SDavid Hildenbrand 	}
663db880b6SDavid Hildenbrand 	storage_increment_size = rnsize << 20;
673db880b6SDavid Hildenbrand 
683db880b6SDavid Hildenbrand 	/* calculate the maximum memory size */
693db880b6SDavid Hildenbrand 	rnmax = ri->rnmax;
703db880b6SDavid Hildenbrand 	if (!rnmax) {
713db880b6SDavid Hildenbrand 		rnmax = ri->rnmax2;
723db880b6SDavid Hildenbrand 	}
733db880b6SDavid Hildenbrand 	max_ram_size = rnmax * storage_increment_size;
743db880b6SDavid Hildenbrand 
753db880b6SDavid Hildenbrand 	/* lowcore is always accessible, so the first increment is accessible */
763db880b6SDavid Hildenbrand 	ram_size = storage_increment_size;
773db880b6SDavid Hildenbrand 
783db880b6SDavid Hildenbrand 	/* probe for r/w memory up to max memory size */
793db880b6SDavid Hildenbrand 	while (ram_size < max_ram_size) {
803db880b6SDavid Hildenbrand 		expect_pgm_int();
813db880b6SDavid Hildenbrand 		cc = tprot(ram_size + storage_increment_size - 1);
823db880b6SDavid Hildenbrand 		/* stop once we receive an exception or have protected memory */
833db880b6SDavid Hildenbrand 		if (clear_pgm_int() || cc != 0)
843db880b6SDavid Hildenbrand 			break;
853db880b6SDavid Hildenbrand 		ram_size += storage_increment_size;
863db880b6SDavid Hildenbrand 	}
8792bbd322SDavid Hildenbrand 
8892bbd322SDavid Hildenbrand 	mem_init(ram_size);
893db880b6SDavid Hildenbrand }
90