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