Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) #include <asm/sclp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) #include <asm/mem_detect.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #include <asm/sparsemem.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include "compressed/decompressor.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include "boot.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) unsigned long __bootdata(max_physmem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) struct mem_detect_info __bootdata(mem_detect);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) /* up to 256 storage elements, 1020 subincrements each */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #define ENTRIES_EXTENDED_MAX						       \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 	(256 * (1020 / 2) * sizeof(struct mem_detect_block))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * To avoid corrupting old kernel memory during dump, find lowest memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * chunk possible either right after the kernel end (decompressed kernel) or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  * after initrd (if it is present and there is no hole between the kernel end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  * and initrd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) static void *mem_detect_alloc_extended(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	unsigned long offset = ALIGN(mem_safe_offset(), sizeof(u64));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	    INITRD_START < offset + ENTRIES_EXTENDED_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 		offset = ALIGN(INITRD_START + INITRD_SIZE, sizeof(u64));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	return (void *)offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) static struct mem_detect_block *__get_mem_detect_block_ptr(u32 n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	if (n < MEM_INLINED_ENTRIES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 		return &mem_detect.entries[n];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	if (unlikely(!mem_detect.entries_extended))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 		mem_detect.entries_extended = mem_detect_alloc_extended();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	return &mem_detect.entries_extended[n - MEM_INLINED_ENTRIES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  * sequential calls to add_mem_detect_block with adjacent memory areas
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  * are merged together into single memory block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) void add_mem_detect_block(u64 start, u64 end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	struct mem_detect_block *block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	if (mem_detect.count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		block = __get_mem_detect_block_ptr(mem_detect.count - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 		if (block->end == start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 			block->end = end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	block = __get_mem_detect_block_ptr(mem_detect.count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	block->start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	block->end = end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	mem_detect.count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) static int __diag260(unsigned long rx1, unsigned long rx2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	register unsigned long _rx1 asm("2") = rx1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	register unsigned long _rx2 asm("3") = rx2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	register unsigned long _ry asm("4") = 0x10; /* storage configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	int rc = -1;				    /* fail */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	unsigned long reg1, reg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	psw_t old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		"	mvc	0(16,%[psw_old]),0(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		"	epsw	%0,%1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		"	st	%0,0(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		"	st	%1,4(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		"	larl	%0,1f\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 		"	stg	%0,8(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 		"	diag	%[rx],%[ry],0x260\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 		"	ipm	%[rc]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 		"	srl	%[rc],28\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		"1:	mvc	0(16,%[psw_pgm]),0(%[psw_old])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 		: "=&d" (reg1), "=&a" (reg2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 		  "+Q" (S390_lowcore.program_new_psw),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 		  "=Q" (old),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 		  [rc] "+&d" (rc), [ry] "+d" (_ry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		: [rx] "d" (_rx1), "d" (_rx2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		  [psw_old] "a" (&old),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		  [psw_pgm] "a" (&S390_lowcore.program_new_psw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		: "cc", "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	return rc == 0 ? _ry : -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static int diag260(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	int rc, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		unsigned long start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		unsigned long end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	} storage_extents[8] __aligned(16); /* VM supports up to 8 extends */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	memset(storage_extents, 0, sizeof(storage_extents));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	rc = __diag260((unsigned long)storage_extents, sizeof(storage_extents));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	if (rc == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	for (i = 0; i < min_t(int, rc, ARRAY_SIZE(storage_extents)); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		add_mem_detect_block(storage_extents[i].start, storage_extents[i].end + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static int tprot(unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	unsigned long reg1, reg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	int rc = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	psw_t old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		"	mvc	0(16,%[psw_old]),0(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		"	epsw	%[reg1],%[reg2]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		"	st	%[reg1],0(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		"	st	%[reg2],4(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		"	larl	%[reg1],1f\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		"	stg	%[reg1],8(%[psw_pgm])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		"	tprot	0(%[addr]),0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 		"	ipm	%[rc]\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 		"	srl	%[rc],28\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		"1:	mvc	0(16,%[psw_pgm]),0(%[psw_old])\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		: [reg1] "=&d" (reg1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		  [reg2] "=&a" (reg2),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		  [rc] "+&d" (rc),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		  "=Q" (S390_lowcore.program_new_psw.addr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		  "=Q" (old)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		: [psw_old] "a" (&old),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		  [psw_pgm] "a" (&S390_lowcore.program_new_psw),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		  [addr] "a" (addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		: "cc", "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static void search_mem_end(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	unsigned long range = 1 << (MAX_PHYSMEM_BITS - 20); /* in 1MB blocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	unsigned long offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	unsigned long pivot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	while (range > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 		range >>= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		pivot = offset + range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		if (!tprot(pivot << 20))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 			offset = pivot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	add_mem_detect_block(0, (offset + 1) << 20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) void detect_memory(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	sclp_early_get_memsize(&max_physmem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	if (!sclp_early_read_storage_info()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		mem_detect.info_source = MEM_DETECT_SCLP_STOR_INFO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	if (!diag260()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		mem_detect.info_source = MEM_DETECT_DIAG260;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	if (max_physmem_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		add_mem_detect_block(0, max_physmem_end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		mem_detect.info_source = MEM_DETECT_SCLP_READ_INFO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	search_mem_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	mem_detect.info_source = MEM_DETECT_BIN_SEARCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	max_physmem_end = get_mem_detect_end();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }