Commit a1e97782 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] x86_64: Port over e820 gap detection from i386

Look for gaps in the e820 memory map to put PCI resources in.

This hopefully fixes problems with the PCI code assigning 32bit BARs MMIO
resources which are >32bit.
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent cf94b62f
...@@ -511,3 +511,62 @@ void __init parse_memopt(char *p, char **from) ...@@ -511,3 +511,62 @@ void __init parse_memopt(char *p, char **from)
end_user_pfn >>= PAGE_SHIFT; end_user_pfn >>= PAGE_SHIFT;
} }
unsigned long pci_mem_start = 0xaeedbabe;
/*
* Search for the biggest gap in the low 32 bits of the e820
* memory space. We pass this space to PCI to assign MMIO resources
* for hotplug or unconfigured devices in.
* Hopefully the BIOS let enough space left.
*/
__init void e820_setup_gap(void)
{
unsigned long gapstart, gapsize;
unsigned long last;
int i;
int found = 0;
last = 0x100000000ull;
gapstart = 0x10000000;
gapsize = 0x400000;
i = e820.nr_map;
while (--i >= 0) {
unsigned long long start = e820.map[i].addr;
unsigned long long end = start + e820.map[i].size;
/*
* Since "last" is at most 4GB, we know we'll
* fit in 32 bits if this condition is true
*/
if (last > end) {
unsigned long gap = last - end;
if (gap > gapsize) {
gapsize = gap;
gapstart = end;
found = 1;
}
}
if (start < last)
last = start;
}
if (!found) {
gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit address range\n"
KERN_ERR "PCI: Unassigned devices with 32bit resource registers may break!\n");
}
/*
* Start allocating dynamic PCI memory a bit into the gap,
* aligned up to the nearest megabyte.
*
* Question: should we try to pad it up a bit (do something
* like " + (gapsize >> 3)" in there too?). We now have the
* technology.
*/
pci_mem_start = (gapstart + 0xfffff) & ~0xfffff;
printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
pci_mem_start, gapstart, gapsize);
}
...@@ -76,9 +76,6 @@ int __initdata acpi_force = 0; ...@@ -76,9 +76,6 @@ int __initdata acpi_force = 0;
int acpi_numa __initdata; int acpi_numa __initdata;
/* For PCI or other memory-mapped resources */
unsigned long pci_mem_start = 0x10000000;
/* Boot loader ID as an integer, for the benefit of proc_dointvec */ /* Boot loader ID as an integer, for the benefit of proc_dointvec */
int bootloader_type; int bootloader_type;
...@@ -495,7 +492,6 @@ static void __init reserve_ebda_region(void) ...@@ -495,7 +492,6 @@ static void __init reserve_ebda_region(void)
void __init setup_arch(char **cmdline_p) void __init setup_arch(char **cmdline_p)
{ {
unsigned long low_mem_size;
unsigned long kernel_end; unsigned long kernel_end;
ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
...@@ -654,13 +650,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -654,13 +650,7 @@ void __init setup_arch(char **cmdline_p)
request_resource(&ioport_resource, &standard_io_resources[i]); request_resource(&ioport_resource, &standard_io_resources[i]);
} }
/* Will likely break when you have unassigned resources with more e820_setup_gap();
than 4GB memory and bridges that don't support more than 4GB.
Doing it properly would require to use pci_alloc_consistent
in this case. */
low_mem_size = ((end_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
if (low_mem_size > pci_mem_start)
pci_mem_start = low_mem_size;
#ifdef CONFIG_GART_IOMMU #ifdef CONFIG_GART_IOMMU
iommu_hole_init(); iommu_hole_init();
......
...@@ -50,6 +50,7 @@ extern void e820_print_map(char *who); ...@@ -50,6 +50,7 @@ extern void e820_print_map(char *who);
extern int e820_mapped(unsigned long start, unsigned long end, unsigned type); extern int e820_mapped(unsigned long start, unsigned long end, unsigned type);
extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end); extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
extern void e820_setup_gap(void);
extern void __init parse_memopt(char *p, char **end); extern void __init parse_memopt(char *p, char **end);
......
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