[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] xen: arm: improve handling of system with non-contiguous RAM regions
commit 2d02b05c77fc5e7c76bf6f112db84bbaa44fdcb5 Author: Ian Campbell <ian.campbell@xxxxxxxxxx> AuthorDate: Mon Dec 2 14:39:05 2013 +0000 Commit: Ian Campbell <ian.campbell@xxxxxxxxxx> CommitDate: Fri Dec 6 11:47:46 2013 +0000 xen: arm: improve handling of system with non-contiguous RAM regions arm32 currently only makes use of memory which is contiguous with the first bank. On the Midway platform this means that we only use 4GB of the 8GB available. Change things to make use of non-contiguous memory regions with the restriction that we require that at least half of the total span of the RAM addresses contain RAM. The frametable is currently not sparse and so this restriction avoids problems with allocating enormous amounts of memory for the frametable to cover holes in the address space and exhausting the actual RAM. 50% is arguably too restrictive. 4GB of RAM requires 32MB of frametable on arm32 and 56M on arm64, so we could probably cope with a lower ratio of actual RAM. However half is nice and conservative. arm64 currently uses all banks without regard for the size of the frametable, which I have observed causing problems on models. Implement that same restriction as arm32 there. Long term we should look at moving to a pfn compression based scheme similar to x86, which removes the holes from the frametable. There were some bogus/outdated comments scattered around this code which I have removed. Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> Tested-by: Julien Grall <julien.grall@xxxxxxxxxx> Acked-by: Julien Grall <julien.grall@xxxxxxxxxx> Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx> --- xen/arch/arm/setup.c | 185 +++++++++++++++++++++++++++++++++----------------- 1 files changed, 122 insertions(+), 63 deletions(-) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 3f894b5..840b04b 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -360,35 +360,80 @@ static paddr_t __init get_xen_paddr(void) #ifdef CONFIG_ARM_32 static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) { - paddr_t ram_start; - paddr_t ram_end; - paddr_t ram_size; + paddr_t ram_start, ram_end, ram_size; + paddr_t contig_start, contig_end; paddr_t s, e; unsigned long ram_pages; unsigned long heap_pages, xenheap_pages, domheap_pages; unsigned long dtb_pages; unsigned long boot_mfn_start, boot_mfn_end; - int i = 0; + int i; void *fdt; - /* TODO: Handle non-contiguous memory bank */ if ( !early_info.mem.nr_banks ) early_panic("No memory bank"); - ram_start = early_info.mem.bank[0].start; + + /* + * We are going to accumulate two regions here. + * + * The first is the bounds of the initial memory region which is + * contiguous with the first bank. For simplicity the xenheap is + * always allocated from this region. + * + * The second is the complete bounds of the regions containing RAM + * (ie. from the lowest RAM address to the highest), which + * includes any holes. + * + * We also track the number of actual RAM pages (i.e. not counting + * the holes). + */ ram_size = early_info.mem.bank[0].size; - ram_end = ram_start + ram_size; + + contig_start = ram_start = early_info.mem.bank[0].start; + contig_end = ram_end = ram_start + ram_size; for ( i = 1; i < early_info.mem.nr_banks; i++ ) { - if ( ram_end != early_info.mem.bank[i].start ) + paddr_t bank_start = early_info.mem.bank[i].start; + paddr_t bank_size = early_info.mem.bank[i].size; + paddr_t bank_end = bank_start + bank_size; + + paddr_t new_ram_size = ram_size + bank_size; + paddr_t new_ram_start = min(ram_start,bank_start); + paddr_t new_ram_end = max(ram_end,bank_end); + + /* + * If the new bank is contiguous with the initial contiguous + * region then incorporate it into the contiguous region. + * + * Otherwise we allow non-contigious regions so long as at + * least half of the total RAM region actually contains + * RAM. We actually fudge this slightly and require that + * adding the current bank does not cause us to violate this + * restriction. + * + * This restriction ensures that the frametable (which is not + * currently sparse) does not consume all available RAM. + */ + if ( bank_start == contig_end ) + contig_end = bank_end; + else if ( bank_end == contig_start ) + contig_start = bank_start; + else if ( 2 * new_ram_size < new_ram_end - new_ram_start ) + /* Would create memory map which is too sparse, so stop here. */ break; - ram_size += early_info.mem.bank[i].size; - ram_end += early_info.mem.bank[i].size; + ram_size = new_ram_size; + ram_start = new_ram_start; + ram_end = new_ram_end; } if ( i != early_info.mem.nr_banks ) - early_printk("WARNING: some memory banks are not used\n"); + { + early_printk("WARNING: only using %d out of %d memory banks\n", + i, early_info.mem.nr_banks); + early_info.mem.nr_banks = i; + } total_pages = ram_pages = ram_size >> PAGE_SHIFT; @@ -403,13 +448,14 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) * We try to allocate the largest xenheap possible within these * constraints. */ - heap_pages = (ram_size >> PAGE_SHIFT); + heap_pages = ram_pages; xenheap_pages = (heap_pages/8 + 0x1fffUL) & ~0x1fffUL; xenheap_pages = max(xenheap_pages, 128UL<<(20-PAGE_SHIFT)); do { - e = consider_modules(ram_start, ram_end, + /* xenheap is always in the initial contiguous region */ + e = consider_modules(contig_start, contig_end, pfn_to_paddr(xenheap_pages), 32<<20, 0); if ( e ) @@ -433,9 +479,6 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) /* * Need a single mapped page for populating bootmem_region_list * and enough mapped pages for copying the DTB. - * - * TODO: The DTB (and other payloads) are assumed to be towards - * the start of RAM. */ dtb_pages = (dtb_size + PAGE_SIZE-1) >> PAGE_SHIFT; boot_mfn_start = xenheap_mfn_end - dtb_pages - 1; @@ -443,47 +486,51 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) init_boot_pages(pfn_to_paddr(boot_mfn_start), pfn_to_paddr(boot_mfn_end)); - /* - * Copy the DTB. - * - * TODO: handle other payloads too. - */ + /* Copy the DTB. */ fdt = mfn_to_virt(alloc_boot_pages(dtb_pages, 1)); copy_from_paddr(fdt, dtb_paddr, dtb_size, BUFFERABLE); device_tree_flattened = fdt; /* Add non-xenheap memory */ - s = ram_start; - while ( s < ram_end ) + for ( i = 0; i < early_info.mem.nr_banks; i++ ) { - paddr_t n = ram_end; + paddr_t bank_start = early_info.mem.bank[i].start; + paddr_t bank_end = bank_start + early_info.mem.bank[i].size; - e = next_module(s, &n); - - if ( e == ~(paddr_t)0 ) + s = bank_start; + while ( s < bank_end ) { - e = n = ram_end; - } + paddr_t n = bank_end; - /* Module in RAM which we cannot see here, due to not handling - * non-contiguous memory regions yet - */ - if ( e > ram_end ) - e = ram_end; + e = next_module(s, &n); - /* Avoid the xenheap */ - if ( s < pfn_to_paddr(xenheap_mfn_start+xenheap_pages) - && pfn_to_paddr(xenheap_mfn_start) < e ) - { - e = pfn_to_paddr(xenheap_mfn_start); - n = pfn_to_paddr(xenheap_mfn_start+xenheap_pages); - } + if ( e == ~(paddr_t)0 ) + { + e = n = ram_end; + } + + /* + * Module in a RAM bank other than the one which we are + * not dealing with here. + */ + if ( e > bank_end ) + e = bank_end; - dt_unreserved_regions(s, e, init_boot_pages, 0); + /* Avoid the xenheap */ + if ( s < pfn_to_paddr(xenheap_mfn_start+xenheap_pages) + && pfn_to_paddr(xenheap_mfn_start) < e ) + { + e = pfn_to_paddr(xenheap_mfn_start); + n = pfn_to_paddr(xenheap_mfn_start+xenheap_pages); + } + + dt_unreserved_regions(s, e, init_boot_pages, 0); - s = n; + s = n; + } } + /* Frame table covers all of RAM region, including holes */ setup_frametable_mappings(ram_start, ram_end); max_page = PFN_DOWN(ram_end); @@ -499,8 +546,8 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) { paddr_t ram_start = ~0; paddr_t ram_end = 0; + paddr_t ram_size = 0; int bank; - unsigned long xenheap_pages = 0; unsigned long dtb_pages; void *fdt; @@ -508,23 +555,33 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) for ( bank = 0 ; bank < early_info.mem.nr_banks; bank++ ) { paddr_t bank_start = early_info.mem.bank[bank].start; - paddr_t bank_size = early_info.mem.bank[bank].size; - paddr_t bank_end = bank_start + bank_size; - unsigned long bank_pages = bank_size >> PAGE_SHIFT; + paddr_t bank_size = early_info.mem.bank[bank].size; + paddr_t bank_end = bank_start + bank_size; paddr_t s, e; - total_pages += bank_pages; - - if ( bank_start < ram_start ) - ram_start = bank_start; - if ( bank_end > ram_end ) - ram_end = bank_end; + paddr_t new_ram_size = ram_size + bank_size; + paddr_t new_ram_start = min(ram_start,bank_start); + paddr_t new_ram_end = max(ram_end,bank_end); + + /* + * We allow non-contigious regions so long as at least half of + * the total RAM region actually contains RAM. We actually + * fudge this slightly and require that adding the current + * bank does not cause us to violate this restriction. + * + * This restriction ensures that the frametable (which is not + * currently sparse) does not consume all available RAM. + */ + if ( bank > 0 && 2 * new_ram_size < new_ram_end - new_ram_start ) + /* Would create memory map which is too sparse, so stop here. */ + break; - xenheap_pages += (bank_size >> PAGE_SHIFT); + ram_start = new_ram_start; + ram_end = new_ram_end; + ram_size = new_ram_size; setup_xenheap_mappings(bank_start>>PAGE_SHIFT, bank_size>>PAGE_SHIFT); - /* XXX we assume that the ram regions are ordered */ s = bank_start; while ( s < bank_end ) { @@ -547,6 +604,15 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) } } + if ( bank != early_info.mem.nr_banks ) + { + early_printk("WARNING: only using %d out of %d memory banks\n", + bank, early_info.mem.nr_banks); + early_info.mem.nr_banks = bank; + } + + total_pages += ram_size >> PAGE_SHIFT; + xenheap_virt_end = XENHEAP_VIRT_START + ram_end - ram_start; xenheap_mfn_start = ram_start >> PAGE_SHIFT; xenheap_mfn_end = ram_end >> PAGE_SHIFT; @@ -554,17 +620,10 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) /* * Need enough mapped pages for copying the DTB. - * - * TODO: The DTB (and other payloads) are assumed to be towards - * the start of RAM. */ dtb_pages = (dtb_size + PAGE_SIZE-1) >> PAGE_SHIFT; - /* - * Copy the DTB. - * - * TODO: handle other payloads too. - */ + /* Copy the DTB. */ fdt = mfn_to_virt(alloc_boot_pages(dtb_pages, 1)); copy_from_paddr(fdt, dtb_paddr, dtb_size, BUFFERABLE); device_tree_flattened = fdt; -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |