summaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/mem_detect.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 10:26:41 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 10:26:41 -0700
commit8f5759aeb88a47448cd92ab55a016d013b154a98 (patch)
treea9c0536e10300a95292b99332171837675af1e16 /arch/s390/mm/mem_detect.c
parente5c4ecdc55b6d824365ba7964bcd3185223f9688 (diff)
parent63aef00b55d37e9fad837a8b38a2c261f0d32041 (diff)
downloadlinux-8f5759aeb88a47448cd92ab55a016d013b154a98.tar.bz2
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux into next
Pull first set of s390 updates from Martin Schwidefsky: "The biggest change in this patchset is conversion from the bootmem bitmaps to the memblock code. This conversion requires two common code patches to introduce the 'physmem' memblock list. We experimented with ticket spinlocks but in the end decided against them as they perform poorly on virtualized systems. But the spinlock cleanup and some small improvements are included. The uaccess code got another optimization, the get_user/put_user calls are now inline again for kernel compiles targeted at z10 or newer machines. This makes the text segment shorter and the code gets a little bit faster. And as always some bug fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (31 commits) s390/lowcore: replace lowcore irb array with a per-cpu variable s390/lowcore: reserve 96 bytes for IRB in lowcore s390/facilities: remove extract-cpu-time facility check s390: require mvcos facility for z10 and newer machines s390/boot: fix boot of compressed kernel built with gcc 4.9 s390/cio: remove weird assignment during argument evaluation s390/time: cast tv_nsec to u64 prior to shift in update_vsyscall s390/oprofile: make return of 0 explicit s390/spinlock: refactor arch_spin_lock_wait[_flags] s390/rwlock: add missing local_irq_restore calls s390/spinlock,rwlock: always to a load-and-test first s390/cio: fix multiple structure definitions s390/spinlock: fix system hang with spin_retry <= 0 s390/appldata: add slab.h for kzalloc/kfree s390/uaccess: provide inline variants of get_user/put_user s390/pci: add some new arch specific pci attributes s390/pci: use pdev->dev.groups for attribute creation s390/pci: use macro for attribute creation s390/pci: improve state check when processing hotplug events s390: split TIF bits into CIF, PIF and TIF bits ...
Diffstat (limited to 'arch/s390/mm/mem_detect.c')
-rw-r--r--arch/s390/mm/mem_detect.c130
1 files changed, 30 insertions, 100 deletions
diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c
index cca388253a39..5535cfe0ee11 100644
--- a/arch/s390/mm/mem_detect.c
+++ b/arch/s390/mm/mem_detect.c
@@ -6,130 +6,60 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/memblock.h>
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <asm/ipl.h>
#include <asm/sclp.h>
#include <asm/setup.h>
#define ADDR2G (1ULL << 31)
-static void find_memory_chunks(struct mem_chunk chunk[], unsigned long maxsize)
+#define CHUNK_READ_WRITE 0
+#define CHUNK_READ_ONLY 1
+
+static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size)
+{
+ memblock_add_range(&memblock.memory, start, size, 0, 0);
+ memblock_add_range(&memblock.physmem, start, size, 0, 0);
+}
+
+void __init detect_memory_memblock(void)
{
unsigned long long memsize, rnmax, rzm;
- unsigned long addr = 0, size;
- int i = 0, type;
+ unsigned long addr, size;
+ int type;
rzm = sclp_get_rzm();
rnmax = sclp_get_rnmax();
memsize = rzm * rnmax;
if (!rzm)
rzm = 1ULL << 17;
- if (sizeof(long) == 4) {
+ if (IS_ENABLED(CONFIG_32BIT)) {
rzm = min(ADDR2G, rzm);
- memsize = memsize ? min(ADDR2G, memsize) : ADDR2G;
+ memsize = min(ADDR2G, memsize);
}
- if (maxsize)
- memsize = memsize ? min((unsigned long)memsize, maxsize) : maxsize;
+ max_physmem_end = memsize;
+ addr = 0;
+ /* keep memblock lists close to the kernel */
+ memblock_set_bottom_up(true);
do {
size = 0;
type = tprot(addr);
do {
size += rzm;
- if (memsize && addr + size >= memsize)
+ if (max_physmem_end && addr + size >= max_physmem_end)
break;
} while (type == tprot(addr + size));
if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) {
- if (memsize && (addr + size > memsize))
- size = memsize - addr;
- chunk[i].addr = addr;
- chunk[i].size = size;
- chunk[i].type = type;
- i++;
+ if (max_physmem_end && (addr + size > max_physmem_end))
+ size = max_physmem_end - addr;
+ memblock_physmem_add(addr, size);
}
addr += size;
- } while (addr < memsize && i < MEMORY_CHUNKS);
-}
-
-/**
- * detect_memory_layout - fill mem_chunk array with memory layout data
- * @chunk: mem_chunk array to be filled
- * @maxsize: maximum address where memory detection should stop
- *
- * Fills the passed in memory chunk array with the memory layout of the
- * machine. The array must have a size of at least MEMORY_CHUNKS and will
- * be fully initialized afterwards.
- * If the maxsize paramater has a value > 0 memory detection will stop at
- * that address. It is guaranteed that all chunks have an ending address
- * that is smaller than maxsize.
- * If maxsize is 0 all memory will be detected.
- */
-void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize)
-{
- unsigned long flags, flags_dat, cr0;
-
- memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
- /*
- * Disable IRQs, DAT and low address protection so tprot does the
- * right thing and we don't get scheduled away with low address
- * protection disabled.
- */
- local_irq_save(flags);
- flags_dat = __arch_local_irq_stnsm(0xfb);
- /*
- * In case DAT was enabled, make sure chunk doesn't reside in vmalloc
- * space. We have disabled DAT and any access to vmalloc area will
- * cause an exception.
- * If DAT was disabled we are called from early ipl code.
- */
- if (test_bit(5, &flags_dat)) {
- if (WARN_ON_ONCE(is_vmalloc_or_module_addr(chunk)))
- goto out;
- }
- __ctl_store(cr0, 0, 0);
- __ctl_clear_bit(0, 28);
- find_memory_chunks(chunk, maxsize);
- __ctl_load(cr0, 0, 0);
-out:
- __arch_local_irq_ssm(flags_dat);
- local_irq_restore(flags);
-}
-EXPORT_SYMBOL(detect_memory_layout);
-
-/*
- * Create memory hole with given address and size.
- */
-void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
- unsigned long size)
-{
- int i;
-
- for (i = 0; i < MEMORY_CHUNKS; i++) {
- struct mem_chunk *chunk = &mem_chunk[i];
-
- if (chunk->size == 0)
- continue;
- if (addr > chunk->addr + chunk->size)
- continue;
- if (addr + size <= chunk->addr)
- continue;
- /* Split */
- if ((addr > chunk->addr) &&
- (addr + size < chunk->addr + chunk->size)) {
- struct mem_chunk *new = chunk + 1;
-
- memmove(new, chunk, (MEMORY_CHUNKS-i-1) * sizeof(*new));
- new->addr = addr + size;
- new->size = chunk->addr + chunk->size - new->addr;
- chunk->size = addr - chunk->addr;
- continue;
- } else if ((addr <= chunk->addr) &&
- (addr + size >= chunk->addr + chunk->size)) {
- memmove(chunk, chunk + 1, (MEMORY_CHUNKS-i-1) * sizeof(*chunk));
- memset(&mem_chunk[MEMORY_CHUNKS-1], 0, sizeof(*chunk));
- } else if (addr + size < chunk->addr + chunk->size) {
- chunk->size = chunk->addr + chunk->size - addr - size;
- chunk->addr = addr + size;
- } else if (addr > chunk->addr) {
- chunk->size = addr - chunk->addr;
- }
- }
+ } while (addr < max_physmem_end);
+ memblock_set_bottom_up(false);
+ if (!max_physmem_end)
+ max_physmem_end = memblock_end_of_DRAM();
}