Shuo Liu has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/83264?usp=email )
Change subject: cpu/x86/mtrr: Fill holes for above 4G MMIO window ......................................................................
cpu/x86/mtrr: Fill holes for above 4G MMIO window
Many SoCs will have MMIO high window above 4G, fill holes for them as well to avoid MTRR segmentation and MTRR register insufficiency.
Change-Id: If7d9a91cfb1c5cf1bd21d62775de4eafb7b90aba Signed-off-by: Shuo Liu shuo.liu@intel.com --- M src/cpu/x86/mtrr/mtrr.c 1 file changed, 96 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/64/83264/1
diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c index 6d726f5..ae5f379 100644 --- a/src/cpu/x86/mtrr/mtrr.c +++ b/src/cpu/x86/mtrr/mtrr.c @@ -20,6 +20,7 @@ #include <cpu/x86/mtrr.h> #include <device/device.h> #include <device/pci_ids.h> +#include <lib.h> #include <memrange.h> #include <string.h> #include <types.h> @@ -159,6 +160,84 @@ range_entry_size(r), range_entry_tag(r)); }
+static struct range_entry *detect_mmio_high_window(struct range_entry *entry, + resource_t *base, resource_t *limit) +{ + resource_t mmio_min, mmio_max; + mmio_min = mmio_max = 0; + + struct range_entry *cur, *prev, *ahead; + prev = ahead = NULL; + + for (cur = entry; cur != NULL; cur = cur->next) { + if (!prev) { + prev = cur; + continue; + } + if (cur->begin < RANGE_TO_PHYS_ADDR(RANGE_4GB)) + continue; + + if (cur->tag != MTRR_TYPE_UNCACHEABLE) { + if (mmio_min && mmio_max) + break; + } else { + if (!mmio_min) { + mmio_min = cur->begin; + ahead = prev; + } + mmio_max = cur->end; + } + + prev = cur; + } + + if ((!mmio_min) && (!mmio_max)) + return NULL; + + printk(BIOS_DEBUG, "detected MMIO high window: %llx - %llx\n", mmio_min, mmio_max); + + /* Expand the region downwards for better power of 2 MTRR coverage */ + resource_t low = range_entry_end(ahead); + resource_t high = mmio_min; + resource_t mmio_temp, mmio_base = 0; + resource_t temp = (1ULL << log2_64(mmio_min)); + while (temp) { + mmio_temp = mmio_base + temp; + if (mmio_temp <= high) + mmio_base = mmio_temp; + if (mmio_base >= low) + break; + temp >>= 1; + } + + low = mmio_max; + high = cur->next ? (cur->next->begin - 1) : ((1ULL << cpu_phys_address_size()) - 1); + temp = (1ULL << log2_64(mmio_max)); + resource_t mmio_limit = 0; + while (temp) { + mmio_temp = mmio_limit + temp; + if (mmio_temp <= high) + mmio_limit = mmio_temp; + if (mmio_limit >= low) + break; + temp >>= 1; + } + + /* round the window size to 4KB */ + mmio_limit -= (mmio_limit - mmio_base + 1) & (4 * KiB - 1); + if (mmio_limit < mmio_max) + mmio_limit = mmio_max; + + printk(BIOS_DEBUG, "expanded MMIO high window: %llx - %llx\n", mmio_base, mmio_limit); + + if (base) + *base = mmio_base; + if (limit) + *limit = mmio_limit; + + return cur; +} + static struct memranges *get_physical_address_space(void) { static struct memranges *addr_space; @@ -197,6 +276,23 @@ RANGE_TO_PHYS_ADDR(RANGE_4GB), MTRR_TYPE_UNCACHEABLE);
+ /* + * Many SoCs will have MMIO high window above 4G, fill holes for + * them as well to avoid MTRR segmentation and MTRR register + * insufficiency */ + struct range_entry *entry = addr_space->entries; + do { + resource_t mmio_high_base = 0; + resource_t mmio_high_limit = 0; + entry = detect_mmio_high_window(entry, + &mmio_high_base, &mmio_high_limit); + if (mmio_high_base >= RANGE_TO_PHYS_ADDR(RANGE_4GB) && + mmio_high_base <= mmio_high_limit) + memranges_fill_holes_from_to(addr_space, mmio_high_base, + mmio_high_limit + 1, + MTRR_TYPE_UNCACHEABLE); + } while (entry); + print_physical_address_space(addr_space, NULL); }