Commit 752bea4a authored by Yinghai Lu's avatar Yinghai Lu Committed by Ingo Molnar

x86: reserve dma32 early for gart

a system with 256 GB of RAM, when NUMA is disabled crashes the
following way:

Your BIOS doesn't leave a aperture memory hole
Please enable the IOMMU option in the BIOS setup
This costs you 64 MB of RAM
Cannot allocate aperture memory hole (ffff8101c0000000,65536K)
Kernel panic - not syncing: Not enough memory for aperture
Pid: 0, comm: swapper Not tainted 2.6.25-rc4-x86-latest.git #33

Call Trace:
 [<ffffffff84037c62>] panic+0xb2/0x190
 [<ffffffff840381fc>] ? release_console_sem+0x7c/0x250
 [<ffffffff847b1628>] ? __alloc_bootmem_nopanic+0x48/0x90
 [<ffffffff847b0ac9>] ? free_bootmem+0x29/0x50
 [<ffffffff847ac1f7>] gart_iommu_hole_init+0x5e7/0x680
 [<ffffffff847b255b>] ? alloc_large_system_hash+0x16b/0x310
 [<ffffffff84506a2f>] ? _etext+0x0/0x1
 [<ffffffff847a2e8c>] pci_iommu_alloc+0x1c/0x40
 [<ffffffff847ac795>] mem_init+0x45/0x1a0
 [<ffffffff8479ff35>] start_kernel+0x295/0x380
 [<ffffffff8479f1c2>] _sinittext+0x1c2/0x230

the root cause is : memmap PMD is too big,
[ffffe200e0600000-ffffe200e07fffff] PMD ->ffff81383c000000 on node 0
almost near 4G..., and vmemmap_alloc_block will use up the ram under 4G.

solution will be:
1. make memmap allocation get memory above 4G...
2. reserve some dma32 range early before we try to set up memmap for all.
and release that before pci_iommu_alloc, so gart or swiotlb could get some
range under 4g limit for sure.

the patch is using method 2.
because method1 may need more code to handle SPARSEMEM and SPASEMEM_VMEMMAP

will get
Your BIOS doesn't leave a aperture memory hole
Please enable the IOMMU option in the BIOS setup
This costs you 64 MB of RAM
Mapping aperture over 65536 KB of RAM @ 4000000
Memory: 264245736k/268959744k available (8484k kernel code, 4187464k reserved, 4004k data, 724k init)
Signed-off-by: default avatarYinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 6ec6e0d9
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/dmar.h> #include <linux/dmar.h>
#include <linux/bootmem.h>
#include <asm/proto.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/gart.h> #include <asm/gart.h>
#include <asm/calgary.h> #include <asm/calgary.h>
...@@ -286,8 +288,55 @@ static __init int iommu_setup(char *p) ...@@ -286,8 +288,55 @@ static __init int iommu_setup(char *p)
} }
early_param("iommu", iommu_setup); early_param("iommu", iommu_setup);
static __initdata void *dma32_bootmem_ptr;
static unsigned long dma32_bootmem_size __initdata = (128ULL<<20);
static int __init parse_dma32_size_opt(char *p)
{
if (!p)
return -EINVAL;
dma32_bootmem_size = memparse(p, &p);
return 0;
}
early_param("dma32_size", parse_dma32_size_opt);
void __init dma32_reserve_bootmem(void)
{
unsigned long size, align;
if (end_pfn <= MAX_DMA32_PFN)
return;
align = 64ULL<<20;
size = round_up(dma32_bootmem_size, align);
dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align,
__pa(MAX_DMA_ADDRESS));
if (dma32_bootmem_ptr)
dma32_bootmem_size = size;
else
dma32_bootmem_size = 0;
}
static void __init dma32_free_bootmem(void)
{
int node;
if (end_pfn <= MAX_DMA32_PFN)
return;
if (!dma32_bootmem_ptr)
return;
for_each_online_node(node)
free_bootmem_node(NODE_DATA(node), __pa(dma32_bootmem_ptr),
dma32_bootmem_size);
dma32_bootmem_ptr = NULL;
dma32_bootmem_size = 0;
}
void __init pci_iommu_alloc(void) void __init pci_iommu_alloc(void)
{ {
/* free the range so iommu could get some range less than 4G */
dma32_free_bootmem();
/* /*
* The order of these functions is important for * The order of these functions is important for
* fall-back/fail-over reasons * fall-back/fail-over reasons
......
...@@ -398,6 +398,8 @@ void __init setup_arch(char **cmdline_p) ...@@ -398,6 +398,8 @@ void __init setup_arch(char **cmdline_p)
early_res_to_bootmem(); early_res_to_bootmem();
dma32_reserve_bootmem();
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
/* /*
* Reserve low memory region for sleep support. * Reserve low memory region for sleep support.
......
...@@ -22,6 +22,7 @@ extern int (*pci_config_read)(int seg, int bus, int dev, int fn, ...@@ -22,6 +22,7 @@ extern int (*pci_config_read)(int seg, int bus, int dev, int fn,
extern int (*pci_config_write)(int seg, int bus, int dev, int fn, extern int (*pci_config_write)(int seg, int bus, int dev, int fn,
int reg, int len, u32 value); int reg, int len, u32 value);
extern void dma32_reserve_bootmem(void);
extern void pci_iommu_alloc(void); extern void pci_iommu_alloc(void);
/* The PCI address space does equal the physical memory /* The PCI address space does equal the physical memory
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment