Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cec08e7a authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras
Browse files

[POWERPC] vmemmap fixes to use smaller pages



This changes vmemmap to use a different region (region 0xf) of the
address space, and to configure the page size of that region
dynamically at boot.

The problem with the current approach of always using 16M pages is that
it's not well suited to machines that have small amounts of memory such
as small partitions on pseries, or PS3's.

In fact, on the PS3, failure to allocate the 16M page backing vmmemmap
tends to prevent hotplugging the HV's "additional" memory, thus limiting
the available memory even more, from my experience down to something
like 80M total, which makes it really not very useable.

The logic used by my match to choose the vmemmap page size is:

 - If 16M pages are available and there's 1G or more RAM at boot,
   use that size.
 - Else if 64K pages are available, use that
 - Else use 4K pages

I've tested on a POWER6 (16M pages) and on an iSeries POWER3 (4K pages)
and it seems to work fine.

Note that I intend to change the way we organize the kernel regions &
SLBs so the actual region will change from 0xf back to something else at
one point, as I simplify the SLB miss handler, but that will be for a
later patch.

Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 08fcf1d6
Loading
Loading
Loading
Loading
+26 −2
Original line number Diff line number Diff line
@@ -94,6 +94,9 @@ unsigned long htab_hash_mask;
int mmu_linear_psize = MMU_PAGE_4K;
int mmu_virtual_psize = MMU_PAGE_4K;
int mmu_vmalloc_psize = MMU_PAGE_4K;
#ifdef CONFIG_SPARSEMEM_VMEMMAP
int mmu_vmemmap_psize = MMU_PAGE_4K;
#endif
int mmu_io_psize = MMU_PAGE_4K;
int mmu_kernel_ssize = MMU_SEGSIZE_256M;
int mmu_highuser_ssize = MMU_SEGSIZE_256M;
@@ -387,11 +390,32 @@ static void __init htab_init_page_sizes(void)
	}
#endif /* CONFIG_PPC_64K_PAGES */

#ifdef CONFIG_SPARSEMEM_VMEMMAP
	/* We try to use 16M pages for vmemmap if that is supported
	 * and we have at least 1G of RAM at boot
	 */
	if (mmu_psize_defs[MMU_PAGE_16M].shift &&
	    lmb_phys_mem_size() >= 0x40000000)
		mmu_vmemmap_psize = MMU_PAGE_16M;
	else if (mmu_psize_defs[MMU_PAGE_64K].shift)
		mmu_vmemmap_psize = MMU_PAGE_64K;
	else
		mmu_vmemmap_psize = MMU_PAGE_4K;
#endif /* CONFIG_SPARSEMEM_VMEMMAP */

	printk(KERN_DEBUG "Page orders: linear mapping = %d, "
	       "virtual = %d, io = %d\n",
	       "virtual = %d, io = %d"
#ifdef CONFIG_SPARSEMEM_VMEMMAP
	       ", vmemmap = %d"
#endif
	       "\n",
	       mmu_psize_defs[mmu_linear_psize].shift,
	       mmu_psize_defs[mmu_virtual_psize].shift,
	       mmu_psize_defs[mmu_io_psize].shift);
	       mmu_psize_defs[mmu_io_psize].shift
#ifdef CONFIG_SPARSEMEM_VMEMMAP
	       ,mmu_psize_defs[mmu_vmemmap_psize].shift
#endif
	       );

#ifdef CONFIG_HUGETLB_PAGE
	/* Init large page size. Currently, we pick 16M or 1M depending
+6 −4
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
 *
 */

#undef DEBUG

#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -213,7 +215,7 @@ int __meminit vmemmap_populate(struct page *start_page,
	unsigned long mode_rw;
	unsigned long start = (unsigned long)start_page;
	unsigned long end = (unsigned long)(start_page + nr_pages);
	unsigned long page_size = 1 << mmu_psize_defs[mmu_linear_psize].shift;
	unsigned long page_size = 1 << mmu_psize_defs[mmu_vmemmap_psize].shift;

	mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX;

@@ -235,11 +237,11 @@ int __meminit vmemmap_populate(struct page *start_page,
			start, p, __pa(p));

		mapped = htab_bolt_mapping(start, start + page_size,
					__pa(p), mode_rw, mmu_linear_psize,
					__pa(p), mode_rw, mmu_vmemmap_psize,
					mmu_kernel_ssize);
		BUG_ON(mapped < 0);
	}

	return 0;
}
#endif
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
+14 −2
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@
#include <asm/udbg.h>

#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
#define DBG(fmt...) printk(fmt)
#else
#define DBG pr_debug
#endif
@@ -263,13 +263,19 @@ void slb_initialize(void)
	extern unsigned int *slb_miss_kernel_load_linear;
	extern unsigned int *slb_miss_kernel_load_io;
	extern unsigned int *slb_compare_rr_to_size;
#ifdef CONFIG_SPARSEMEM_VMEMMAP
	extern unsigned int *slb_miss_kernel_load_vmemmap;
	unsigned long vmemmap_llp;
#endif

	/* Prepare our SLB miss handler based on our page size */
	linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
	io_llp = mmu_psize_defs[mmu_io_psize].sllp;
	vmalloc_llp = mmu_psize_defs[mmu_vmalloc_psize].sllp;
	get_paca()->vmalloc_sllp = SLB_VSID_KERNEL | vmalloc_llp;

#ifdef CONFIG_SPARSEMEM_VMEMMAP
	vmemmap_llp = mmu_psize_defs[mmu_vmemmap_psize].sllp;
#endif
	if (!slb_encoding_inited) {
		slb_encoding_inited = 1;
		patch_slb_encoding(slb_miss_kernel_load_linear,
@@ -281,6 +287,12 @@ void slb_initialize(void)

		DBG("SLB: linear  LLP = %04lx\n", linear_llp);
		DBG("SLB: io      LLP = %04lx\n", io_llp);

#ifdef CONFIG_SPARSEMEM_VMEMMAP
		patch_slb_encoding(slb_miss_kernel_load_vmemmap,
				   SLB_VSID_KERNEL | vmemmap_llp);
		DBG("SLB: vmemmap LLP = %04lx\n", vmemmap_llp);
#endif
	}

	get_paca()->stab_rr = SLB_NUM_BOLTED;
+13 −3
Original line number Diff line number Diff line
@@ -47,8 +47,7 @@ _GLOBAL(slb_allocate_realmode)
	 * it to VSID 0, which is reserved as a bad VSID - one which
	 * will never have any pages in it.  */

	/* Check if hitting the linear mapping of the vmalloc/ioremap
	 * kernel space
	/* Check if hitting the linear mapping or some other kernel space
	*/
	bne	cr7,1f

@@ -62,7 +61,18 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT)
	b	slb_finish_load_1T

1:	/* vmalloc/ioremap mapping encoding bits, the "li" instructions below
1:
#ifdef CONFIG_SPARSEMEM_VMEMMAP
	/* Check virtual memmap region. To be patches at kernel boot */
	cmpldi	cr0,r9,0xf
	bne	1f
_GLOBAL(slb_miss_kernel_load_vmemmap)
	li	r11,0
	b	6f
1:
#endif /* CONFIG_SPARSEMEM_VMEMMAP */

	/* vmalloc/ioremap mapping encoding bits, the "li" instructions below
	 * will be patched by the kernel at boot
	 */
BEGIN_FTR_SECTION
+1 −0
Original line number Diff line number Diff line
@@ -177,6 +177,7 @@ extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
extern int mmu_linear_psize;
extern int mmu_virtual_psize;
extern int mmu_vmalloc_psize;
extern int mmu_vmemmap_psize;
extern int mmu_io_psize;
extern int mmu_kernel_ssize;
extern int mmu_highuser_ssize;
Loading