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