2 * Copyright IBM Corp. 2008, 2009
4 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
11 #include <asm/setup.h>
13 #define ADDR2G (1ULL << 31)
15 static void find_memory_chunks(struct mem_chunk chunk
[], unsigned long maxsize
)
17 unsigned long long memsize
, rnmax
, rzm
;
18 unsigned long addr
= 0, size
;
22 rnmax
= sclp_get_rnmax();
23 memsize
= rzm
* rnmax
;
26 if (sizeof(long) == 4) {
27 rzm
= min(ADDR2G
, rzm
);
28 memsize
= memsize
? min(ADDR2G
, memsize
) : ADDR2G
;
31 memsize
= memsize
? min((unsigned long)memsize
, maxsize
) : maxsize
;
37 if (memsize
&& addr
+ size
>= memsize
)
39 } while (type
== tprot(addr
+ size
));
40 if (type
== CHUNK_READ_WRITE
|| type
== CHUNK_READ_ONLY
) {
41 if (memsize
&& (addr
+ size
> memsize
))
42 size
= memsize
- addr
;
49 } while (addr
< memsize
&& i
< MEMORY_CHUNKS
);
53 * detect_memory_layout - fill mem_chunk array with memory layout data
54 * @chunk: mem_chunk array to be filled
55 * @maxsize: maximum address where memory detection should stop
57 * Fills the passed in memory chunk array with the memory layout of the
58 * machine. The array must have a size of at least MEMORY_CHUNKS and will
59 * be fully initialized afterwards.
60 * If the maxsize paramater has a value > 0 memory detection will stop at
61 * that address. It is guaranteed that all chunks have an ending address
62 * that is smaller than maxsize.
63 * If maxsize is 0 all memory will be detected.
65 void detect_memory_layout(struct mem_chunk chunk
[], unsigned long maxsize
)
67 unsigned long flags
, flags_dat
, cr0
;
69 memset(chunk
, 0, MEMORY_CHUNKS
* sizeof(struct mem_chunk
));
71 * Disable IRQs, DAT and low address protection so tprot does the
72 * right thing and we don't get scheduled away with low address
73 * protection disabled.
75 local_irq_save(flags
);
76 flags_dat
= __arch_local_irq_stnsm(0xfb);
78 * In case DAT was enabled, make sure chunk doesn't reside in vmalloc
79 * space. We have disabled DAT and any access to vmalloc area will
81 * If DAT was disabled we are called from early ipl code.
83 if (test_bit(5, &flags_dat
)) {
84 if (WARN_ON_ONCE(is_vmalloc_or_module_addr(chunk
)))
87 __ctl_store(cr0
, 0, 0);
88 __ctl_clear_bit(0, 28);
89 find_memory_chunks(chunk
, maxsize
);
90 __ctl_load(cr0
, 0, 0);
92 __arch_local_irq_ssm(flags_dat
);
93 local_irq_restore(flags
);
95 EXPORT_SYMBOL(detect_memory_layout
);
98 * Create memory hole with given address and size.
100 void create_mem_hole(struct mem_chunk mem_chunk
[], unsigned long addr
,
105 for (i
= 0; i
< MEMORY_CHUNKS
; i
++) {
106 struct mem_chunk
*chunk
= &mem_chunk
[i
];
108 if (chunk
->size
== 0)
110 if (addr
> chunk
->addr
+ chunk
->size
)
112 if (addr
+ size
<= chunk
->addr
)
115 if ((addr
> chunk
->addr
) &&
116 (addr
+ size
< chunk
->addr
+ chunk
->size
)) {
117 struct mem_chunk
*new = chunk
+ 1;
119 memmove(new, chunk
, (MEMORY_CHUNKS
-i
-1) * sizeof(*new));
120 new->addr
= addr
+ size
;
121 new->size
= chunk
->addr
+ chunk
->size
- new->addr
;
122 chunk
->size
= addr
- chunk
->addr
;
124 } else if ((addr
<= chunk
->addr
) &&
125 (addr
+ size
>= chunk
->addr
+ chunk
->size
)) {
126 memset(chunk
, 0 , sizeof(*chunk
));
127 } else if (addr
+ size
< chunk
->addr
+ chunk
->size
) {
128 chunk
->size
= chunk
->addr
+ chunk
->size
- addr
- size
;
129 chunk
->addr
= addr
+ size
;
130 } else if (addr
> chunk
->addr
) {
131 chunk
->size
= addr
- chunk
->addr
;