diff options
-rw-r--r-- | arch/x86_64/kernel/e820.c | 59 | ||||
-rw-r--r-- | arch/x86_64/kernel/setup.c | 12 | ||||
-rw-r--r-- | include/asm-x86_64/e820.h | 1 |
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 | ||
514 | unsigned 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 | ||
77 | int acpi_numa __initdata; | 77 | int acpi_numa __initdata; |
78 | 78 | ||
79 | /* For PCI or other memory-mapped resources */ | ||
80 | unsigned 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 */ |
83 | int bootloader_type; | 80 | int bootloader_type; |
84 | 81 | ||
@@ -495,7 +492,6 @@ static void __init reserve_ebda_region(void) | |||
495 | 492 | ||
496 | void __init setup_arch(char **cmdline_p) | 493 | void __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); | |||
50 | extern int e820_mapped(unsigned long start, unsigned long end, unsigned type); | 50 | extern int e820_mapped(unsigned long start, unsigned long end, unsigned type); |
51 | 51 | ||
52 | extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end); | 52 | extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end); |
53 | extern void e820_setup_gap(void); | ||
53 | 54 | ||
54 | extern void __init parse_memopt(char *p, char **end); | 55 | extern void __init parse_memopt(char *p, char **end); |
55 | 56 | ||