aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2005-04-16 18:25:12 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:25:12 -0400
commita1e9778203b15b86bc2219e87478d3be9acce735 (patch)
tree15141c5b56a4e39fa8e879812785e957ea720c9b
parentcf94b62f7005805be0a3ba02c624cb8cd3595bac (diff)
[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: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/x86_64/kernel/e820.c59
-rw-r--r--arch/x86_64/kernel/setup.c12
-rw-r--r--include/asm-x86_64/e820.h1
3 files changed, 61 insertions, 11 deletions
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index 657003e461e6..56516ac92e5d 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -511,3 +511,62 @@ void __init parse_memopt(char *p, char **from)
511 end_user_pfn >>= PAGE_SHIFT; 511 end_user_pfn >>= PAGE_SHIFT;
512} 512}
513 513
514unsigned long pci_mem_start = 0xaeedbabe;
515
516/*
517 * Search for the biggest gap in the low 32 bits of the e820
518 * memory space. We pass this space to PCI to assign MMIO resources
519 * for hotplug or unconfigured devices in.
520 * Hopefully the BIOS let enough space left.
521 */
522__init void e820_setup_gap(void)
523{
524 unsigned long gapstart, gapsize;
525 unsigned long last;
526 int i;
527 int found = 0;
528
529 last = 0x100000000ull;
530 gapstart = 0x10000000;
531 gapsize = 0x400000;
532 i = e820.nr_map;
533 while (--i >= 0) {
534 unsigned long long start = e820.map[i].addr;
535 unsigned long long end = start + e820.map[i].size;
536
537 /*
538 * Since "last" is at most 4GB, we know we'll
539 * fit in 32 bits if this condition is true
540 */
541 if (last > end) {
542 unsigned long gap = last - end;
543
544 if (gap > gapsize) {
545 gapsize = gap;
546 gapstart = end;
547 found = 1;
548 }
549 }
550 if (start < last)
551 last = start;
552 }
553
554 if (!found) {
555 gapstart = (end_pfn << PAGE_SHIFT) + 1024*1024;
556 printk(KERN_ERR "PCI: Warning: Cannot find a gap in the 32bit address range\n"
557 KERN_ERR "PCI: Unassigned devices with 32bit resource registers may break!\n");
558 }
559
560 /*
561 * Start allocating dynamic PCI memory a bit into the gap,
562 * aligned up to the nearest megabyte.
563 *
564 * Question: should we try to pad it up a bit (do something
565 * like " + (gapsize >> 3)" in there too?). We now have the
566 * technology.
567 */
568 pci_mem_start = (gapstart + 0xfffff) & ~0xfffff;
569
570 printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
571 pci_mem_start, gapstart, gapsize);
572}
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index b06221e31952..57f619052bad 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -76,9 +76,6 @@ int __initdata acpi_force = 0;
76 76
77int acpi_numa __initdata; 77int acpi_numa __initdata;
78 78
79/* For PCI or other memory-mapped resources */
80unsigned long pci_mem_start = 0x10000000;
81
82/* Boot loader ID as an integer, for the benefit of proc_dointvec */ 79/* Boot loader ID as an integer, for the benefit of proc_dointvec */
83int bootloader_type; 80int bootloader_type;
84 81
@@ -495,7 +492,6 @@ static void __init reserve_ebda_region(void)
495 492
496void __init setup_arch(char **cmdline_p) 493void __init setup_arch(char **cmdline_p)
497{ 494{
498 unsigned long low_mem_size;
499 unsigned long kernel_end; 495 unsigned long kernel_end;
500 496
501 ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); 497 ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
@@ -654,13 +650,7 @@ void __init setup_arch(char **cmdline_p)
654 request_resource(&ioport_resource, &standard_io_resources[i]); 650 request_resource(&ioport_resource, &standard_io_resources[i]);
655 } 651 }
656 652
657 /* Will likely break when you have unassigned resources with more 653 e820_setup_gap();
658 than 4GB memory and bridges that don't support more than 4GB.
659 Doing it properly would require to use pci_alloc_consistent
660 in this case. */
661 low_mem_size = ((end_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
662 if (low_mem_size > pci_mem_start)
663 pci_mem_start = low_mem_size;
664 654
665#ifdef CONFIG_GART_IOMMU 655#ifdef CONFIG_GART_IOMMU
666 iommu_hole_init(); 656 iommu_hole_init();
diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
index 5b376e42b153..08f83a4b4f4a 100644
--- a/include/asm-x86_64/e820.h
+++ b/include/asm-x86_64/e820.h
@@ -50,6 +50,7 @@ extern void e820_print_map(char *who);
50extern int e820_mapped(unsigned long start, unsigned long end, unsigned type); 50extern int e820_mapped(unsigned long start, unsigned long end, unsigned type);
51 51
52extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end); 52extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
53extern void e820_setup_gap(void);
53 54
54extern void __init parse_memopt(char *p, char **end); 55extern void __init parse_memopt(char *p, char **end);
55 56