Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | /* SPDX-License-Identifier: GPL-2.0 */ #ifndef _ASM_S390_MEM_DETECT_H #define _ASM_S390_MEM_DETECT_H #include <linux/types.h> #include <asm/page.h> enum physmem_info_source { MEM_DETECT_NONE = 0, MEM_DETECT_SCLP_STOR_INFO, MEM_DETECT_DIAG260, MEM_DETECT_SCLP_READ_INFO, MEM_DETECT_BIN_SEARCH }; struct physmem_range { u64 start; u64 end; }; enum reserved_range_type { RR_DECOMPRESSOR, RR_INITRD, RR_VMLINUX, RR_RELOC, RR_AMODE31, RR_IPLREPORT, RR_CERT_COMP_LIST, RR_MEM_DETECT_EXTENDED, RR_VMEM, RR_MAX }; struct reserved_range { unsigned long start; unsigned long end; struct reserved_range *chain; }; /* * Storage element id is defined as 1 byte (up to 256 storage elements). * In practise only storage element id 0 and 1 are used). * According to architecture one storage element could have as much as * 1020 subincrements. 255 physmem_ranges are embedded in physmem_info. * If more physmem_ranges are required, a block of memory from already * known physmem_range is taken (online_extended points to it). */ #define MEM_INLINED_ENTRIES 255 /* (PAGE_SIZE - 16) / 16 */ struct physmem_info { u32 range_count; u8 info_source; unsigned long usable; struct reserved_range reserved[RR_MAX]; struct physmem_range online[MEM_INLINED_ENTRIES]; struct physmem_range *online_extended; }; extern struct physmem_info physmem_info; void add_physmem_online_range(u64 start, u64 end); static inline int __get_physmem_range(u32 n, unsigned long *start, unsigned long *end, bool respect_usable_limit) { if (n >= physmem_info.range_count) { *start = 0; *end = 0; return -1; } if (n < MEM_INLINED_ENTRIES) { *start = (unsigned long)physmem_info.online[n].start; *end = (unsigned long)physmem_info.online[n].end; } else { *start = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].start; *end = (unsigned long)physmem_info.online_extended[n - MEM_INLINED_ENTRIES].end; } if (respect_usable_limit && physmem_info.usable) { if (*start >= physmem_info.usable) return -1; if (*end > physmem_info.usable) *end = physmem_info.usable; } return 0; } /** * for_each_physmem_usable_range - early online memory range iterator * @i: an integer used as loop variable * @p_start: ptr to unsigned long for start address of the range * @p_end: ptr to unsigned long for end address of the range * * Walks over detected online memory ranges below usable limit. */ #define for_each_physmem_usable_range(i, p_start, p_end) \ for (i = 0; !__get_physmem_range(i, p_start, p_end, true); i++) /* Walks over all detected online memory ranges disregarding usable limit. */ #define for_each_physmem_online_range(i, p_start, p_end) \ for (i = 0; !__get_physmem_range(i, p_start, p_end, false); i++) static inline const char *get_physmem_info_source(void) { switch (physmem_info.info_source) { case MEM_DETECT_SCLP_STOR_INFO: return "sclp storage info"; case MEM_DETECT_DIAG260: return "diag260"; case MEM_DETECT_SCLP_READ_INFO: return "sclp read info"; case MEM_DETECT_BIN_SEARCH: return "binary search"; } return "none"; } #define RR_TYPE_NAME(t) case RR_ ## t: return #t static inline const char *get_rr_type_name(enum reserved_range_type t) { switch (t) { RR_TYPE_NAME(DECOMPRESSOR); RR_TYPE_NAME(INITRD); RR_TYPE_NAME(VMLINUX); RR_TYPE_NAME(AMODE31); RR_TYPE_NAME(IPLREPORT); RR_TYPE_NAME(CERT_COMP_LIST); RR_TYPE_NAME(MEM_DETECT_EXTENDED); RR_TYPE_NAME(VMEM); default: return "UNKNOWN"; } } #define for_each_physmem_reserved_type_range(t, range, p_start, p_end) \ for (range = &physmem_info.reserved[t], *p_start = range->start, *p_end = range->end; \ range && range->end; range = range->chain ? __va(range->chain) : NULL, \ *p_start = range ? range->start : 0, *p_end = range ? range->end : 0) static inline struct reserved_range *__physmem_reserved_next(enum reserved_range_type *t, struct reserved_range *range) { if (!range) { range = &physmem_info.reserved[*t]; if (range->end) return range; } if (range->chain) return __va(range->chain); while (++*t < RR_MAX) { range = &physmem_info.reserved[*t]; if (range->end) return range; } return NULL; } #define for_each_physmem_reserved_range(t, range, p_start, p_end) \ for (t = 0, range = __physmem_reserved_next(&t, NULL), \ *p_start = range ? range->start : 0, *p_end = range ? range->end : 0; \ range; range = __physmem_reserved_next(&t, range), \ *p_start = range ? range->start : 0, *p_end = range ? range->end : 0) static inline unsigned long get_physmem_reserved(enum reserved_range_type type, unsigned long *addr, unsigned long *size) { *addr = physmem_info.reserved[type].start; *size = physmem_info.reserved[type].end - physmem_info.reserved[type].start; return *size; } #endif |