diff options
author | Andi Kleen <ak@suse.de> | 2005-04-16 18:25:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:25:12 -0400 |
commit | a1e9778203b15b86bc2219e87478d3be9acce735 (patch) | |
tree | 15141c5b56a4e39fa8e879812785e957ea720c9b /arch/x86_64/kernel/e820.c | |
parent | cf94b62f7005805be0a3ba02c624cb8cd3595bac (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>
Diffstat (limited to 'arch/x86_64/kernel/e820.c')
-rw-r--r-- | arch/x86_64/kernel/e820.c | 59 |
1 files changed, 59 insertions, 0 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 | } | ||