xref: /openbmc/linux/arch/s390/include/asm/physmem_info.h (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
18c37cb7dSVasily Gorbik /* SPDX-License-Identifier: GPL-2.0 */
28c37cb7dSVasily Gorbik #ifndef _ASM_S390_MEM_DETECT_H
38c37cb7dSVasily Gorbik #define _ASM_S390_MEM_DETECT_H
48c37cb7dSVasily Gorbik 
58c37cb7dSVasily Gorbik #include <linux/types.h>
68c37cb7dSVasily Gorbik #include <asm/page.h>
78c37cb7dSVasily Gorbik 
88c37cb7dSVasily Gorbik enum physmem_info_source {
98c37cb7dSVasily Gorbik 	MEM_DETECT_NONE = 0,
108c37cb7dSVasily Gorbik 	MEM_DETECT_SCLP_STOR_INFO,
118c37cb7dSVasily Gorbik 	MEM_DETECT_DIAG260,
128c37cb7dSVasily Gorbik 	MEM_DETECT_SCLP_READ_INFO,
138c37cb7dSVasily Gorbik 	MEM_DETECT_BIN_SEARCH
148c37cb7dSVasily Gorbik };
158c37cb7dSVasily Gorbik 
168c37cb7dSVasily Gorbik struct physmem_range {
178c37cb7dSVasily Gorbik 	u64 start;
188c37cb7dSVasily Gorbik 	u64 end;
198c37cb7dSVasily Gorbik };
20*f913a660SVasily Gorbik 
21*f913a660SVasily Gorbik enum reserved_range_type {
22*f913a660SVasily Gorbik 	RR_DECOMPRESSOR,
23*f913a660SVasily Gorbik 	RR_INITRD,
24*f913a660SVasily Gorbik 	RR_VMLINUX,
25*f913a660SVasily Gorbik 	RR_AMODE31,
26*f913a660SVasily Gorbik 	RR_IPLREPORT,
27*f913a660SVasily Gorbik 	RR_CERT_COMP_LIST,
28*f913a660SVasily Gorbik 	RR_MEM_DETECT_EXTENDED,
29*f913a660SVasily Gorbik 	RR_VMEM,
30*f913a660SVasily Gorbik 	RR_MAX
31*f913a660SVasily Gorbik };
32*f913a660SVasily Gorbik 
33*f913a660SVasily Gorbik struct reserved_range {
34*f913a660SVasily Gorbik 	unsigned long start;
35*f913a660SVasily Gorbik 	unsigned long end;
36*f913a660SVasily Gorbik 	struct reserved_range *chain;
37*f913a660SVasily Gorbik };
388c37cb7dSVasily Gorbik 
398c37cb7dSVasily Gorbik /*
408c37cb7dSVasily Gorbik  * Storage element id is defined as 1 byte (up to 256 storage elements).
418c37cb7dSVasily Gorbik  * In practise only storage element id 0 and 1 are used).
428c37cb7dSVasily Gorbik  * According to architecture one storage element could have as much as
438c37cb7dSVasily Gorbik  * 1020 subincrements. 255 physmem_ranges are embedded in physmem_info.
448c37cb7dSVasily Gorbik  * If more physmem_ranges are required, a block of memory from already
458c37cb7dSVasily Gorbik  * known physmem_range is taken (online_extended points to it).
468c37cb7dSVasily Gorbik  */
478c37cb7dSVasily Gorbik #define MEM_INLINED_ENTRIES 255 /* (PAGE_SIZE - 16) / 16 */
488c37cb7dSVasily Gorbik 
498c37cb7dSVasily Gorbik struct physmem_info {
508c37cb7dSVasily Gorbik 	u32 range_count;
518c37cb7dSVasily Gorbik 	u8 info_source;
52*f913a660SVasily Gorbik 	unsigned long usable;
538c37cb7dSVasily Gorbik 	struct reserved_range reserved[RR_MAX];
548c37cb7dSVasily Gorbik 	struct physmem_range online[MEM_INLINED_ENTRIES];
558c37cb7dSVasily Gorbik 	struct physmem_range *online_extended;
568c37cb7dSVasily Gorbik };
578c37cb7dSVasily Gorbik 
588c37cb7dSVasily Gorbik extern struct physmem_info physmem_info;
598c37cb7dSVasily Gorbik 
608c37cb7dSVasily Gorbik void add_physmem_online_range(u64 start, u64 end);
618c37cb7dSVasily Gorbik 
__get_physmem_range(u32 n,unsigned long * start,unsigned long * end,bool respect_usable_limit)628c37cb7dSVasily Gorbik static inline int __get_physmem_range(u32 n, unsigned long *start,
638c37cb7dSVasily Gorbik 				      unsigned long *end, bool respect_usable_limit)
648c37cb7dSVasily Gorbik {
658c37cb7dSVasily Gorbik 	if (n >= physmem_info.range_count) {
668c37cb7dSVasily Gorbik 		*start = 0;
678c37cb7dSVasily Gorbik 		*end = 0;
688c37cb7dSVasily Gorbik 		return -1;
698c37cb7dSVasily Gorbik 	}
708c37cb7dSVasily Gorbik 
718c37cb7dSVasily Gorbik 	if (n < MEM_INLINED_ENTRIES) {
728c37cb7dSVasily Gorbik 		*start = (unsigned long)physmem_info.online[n].start;
738c37cb7dSVasily Gorbik 		*end = (unsigned long)physmem_info.online[n].end;
748c37cb7dSVasily Gorbik 	} else {
758c37cb7dSVasily Gorbik 		*start = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].start;
768c37cb7dSVasily Gorbik 		*end = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].end;
778c37cb7dSVasily Gorbik 	}
788c37cb7dSVasily Gorbik 
798c37cb7dSVasily Gorbik 	if (respect_usable_limit && physmem_info.usable) {
808c37cb7dSVasily Gorbik 		if (*start >= physmem_info.usable)
818c37cb7dSVasily Gorbik 			return -1;
828c37cb7dSVasily Gorbik 		if (*end > physmem_info.usable)
838c37cb7dSVasily Gorbik 			*end = physmem_info.usable;
848c37cb7dSVasily Gorbik 	}
858c37cb7dSVasily Gorbik 	return 0;
868c37cb7dSVasily Gorbik }
878c37cb7dSVasily Gorbik 
888c37cb7dSVasily Gorbik /**
898c37cb7dSVasily Gorbik  * for_each_physmem_usable_range - early online memory range iterator
908c37cb7dSVasily Gorbik  * @i: an integer used as loop variable
918c37cb7dSVasily Gorbik  * @p_start: ptr to unsigned long for start address of the range
928c37cb7dSVasily Gorbik  * @p_end: ptr to unsigned long for end address of the range
938c37cb7dSVasily Gorbik  *
948c37cb7dSVasily Gorbik  * Walks over detected online memory ranges below usable limit.
958c37cb7dSVasily Gorbik  */
968c37cb7dSVasily Gorbik #define for_each_physmem_usable_range(i, p_start, p_end)		\
978c37cb7dSVasily Gorbik 	for (i = 0; !__get_physmem_range(i, p_start, p_end, true); i++)
988c37cb7dSVasily Gorbik 
998c37cb7dSVasily Gorbik /* Walks over all detected online memory ranges disregarding usable limit. */
1008c37cb7dSVasily Gorbik #define for_each_physmem_online_range(i, p_start, p_end)		\
1018c37cb7dSVasily Gorbik 	for (i = 0; !__get_physmem_range(i, p_start, p_end, false); i++)
102*f913a660SVasily Gorbik 
get_physmem_info_source(void)103*f913a660SVasily Gorbik static inline const char *get_physmem_info_source(void)
104*f913a660SVasily Gorbik {
105*f913a660SVasily Gorbik 	switch (physmem_info.info_source) {
106*f913a660SVasily Gorbik 	case MEM_DETECT_SCLP_STOR_INFO:
107*f913a660SVasily Gorbik 		return "sclp storage info";
108*f913a660SVasily Gorbik 	case MEM_DETECT_DIAG260:
109*f913a660SVasily Gorbik 		return "diag260";
110*f913a660SVasily Gorbik 	case MEM_DETECT_SCLP_READ_INFO:
111*f913a660SVasily Gorbik 		return "sclp read info";
112*f913a660SVasily Gorbik 	case MEM_DETECT_BIN_SEARCH:
113*f913a660SVasily Gorbik 		return "binary search";
114*f913a660SVasily Gorbik 	}
115*f913a660SVasily Gorbik 	return "none";
116*f913a660SVasily Gorbik }
117*f913a660SVasily Gorbik 
118*f913a660SVasily Gorbik #define RR_TYPE_NAME(t) case RR_ ## t: return #t
get_rr_type_name(enum reserved_range_type t)119*f913a660SVasily Gorbik static inline const char *get_rr_type_name(enum reserved_range_type t)
120*f913a660SVasily Gorbik {
121*f913a660SVasily Gorbik 	switch (t) {
122*f913a660SVasily Gorbik 	RR_TYPE_NAME(DECOMPRESSOR);
123*f913a660SVasily Gorbik 	RR_TYPE_NAME(INITRD);
124*f913a660SVasily Gorbik 	RR_TYPE_NAME(VMLINUX);
125*f913a660SVasily Gorbik 	RR_TYPE_NAME(AMODE31);
126*f913a660SVasily Gorbik 	RR_TYPE_NAME(IPLREPORT);
127*f913a660SVasily Gorbik 	RR_TYPE_NAME(CERT_COMP_LIST);
128*f913a660SVasily Gorbik 	RR_TYPE_NAME(MEM_DETECT_EXTENDED);
129*f913a660SVasily Gorbik 	RR_TYPE_NAME(VMEM);
130*f913a660SVasily Gorbik 	default:
131*f913a660SVasily Gorbik 		return "UNKNOWN";
132*f913a660SVasily Gorbik 	}
133*f913a660SVasily Gorbik }
134*f913a660SVasily Gorbik 
135*f913a660SVasily Gorbik #define for_each_physmem_reserved_type_range(t, range, p_start, p_end)				\
136*f913a660SVasily Gorbik 	for (range = &physmem_info.reserved[t], *p_start = range->start, *p_end = range->end;	\
137*f913a660SVasily Gorbik 	     range && range->end; range = range->chain ? __va(range->chain) : NULL,		\
138*f913a660SVasily Gorbik 	     *p_start = range ? range->start : 0, *p_end = range ? range->end : 0)
139*f913a660SVasily Gorbik 
__physmem_reserved_next(enum reserved_range_type * t,struct reserved_range * range)140*f913a660SVasily Gorbik static inline struct reserved_range *__physmem_reserved_next(enum reserved_range_type *t,
141*f913a660SVasily Gorbik 							     struct reserved_range *range)
142*f913a660SVasily Gorbik {
143*f913a660SVasily Gorbik 	if (!range) {
144*f913a660SVasily Gorbik 		range = &physmem_info.reserved[*t];
145*f913a660SVasily Gorbik 		if (range->end)
146*f913a660SVasily Gorbik 			return range;
147*f913a660SVasily Gorbik 	}
148*f913a660SVasily Gorbik 	if (range->chain)
149*f913a660SVasily Gorbik 		return __va(range->chain);
150*f913a660SVasily Gorbik 	while (++*t < RR_MAX) {
151*f913a660SVasily Gorbik 		range = &physmem_info.reserved[*t];
152*f913a660SVasily Gorbik 		if (range->end)
153*f913a660SVasily Gorbik 			return range;
154*f913a660SVasily Gorbik 	}
155*f913a660SVasily Gorbik 	return NULL;
156*f913a660SVasily Gorbik }
157*f913a660SVasily Gorbik 
158*f913a660SVasily Gorbik #define for_each_physmem_reserved_range(t, range, p_start, p_end)			\
159*f913a660SVasily Gorbik 	for (t = 0, range = __physmem_reserved_next(&t, NULL),			\
160*f913a660SVasily Gorbik 	    *p_start = range ? range->start : 0, *p_end = range ? range->end : 0;	\
161*f913a660SVasily Gorbik 	     range; range = __physmem_reserved_next(&t, range),			\
162*f913a660SVasily Gorbik 	    *p_start = range ? range->start : 0, *p_end = range ? range->end : 0)
163*f913a660SVasily Gorbik 
get_physmem_reserved(enum reserved_range_type type,unsigned long * addr,unsigned long * size)164*f913a660SVasily Gorbik static inline unsigned long get_physmem_reserved(enum reserved_range_type type,
1658c37cb7dSVasily Gorbik 						 unsigned long *addr, unsigned long *size)
166*f913a660SVasily Gorbik {
167*f913a660SVasily Gorbik 	*addr = physmem_info.reserved[type].start;
168*f913a660SVasily Gorbik 	*size = physmem_info.reserved[type].end - physmem_info.reserved[type].start;
1698c37cb7dSVasily Gorbik 	return *size;
1708c37cb7dSVasily Gorbik }
1718c37cb7dSVasily Gorbik 
172 #endif
173