Aaron Durbin (adurbin@google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/5169
-gerrit
commit 05efa9e58f2488fa611257c6296d10f20d06bca0 Author: Aaron Durbin adurbin@chromium.org Date: Sat Feb 8 15:41:52 2014 -0600
mtrr: only add prefetchable resources as WRCOMB for VGA devices
Be more conservative and only add VGA devices' prefetchable resources as write-combining in the address space. Previously all prefetchable memory was added as a write-combining memory type. Some hardware incorrectly advertises its BAR as prefetchable when it shouldn't be.
A new memranges_add_resources_filter() function is added to provide additional filtering on device and resource.
Change-Id: I3fc55b90d8c5b694c5aa9e2f34db1b4ef845ce10 Signed-off-by: Aaron Durbin adurbin@chromium.org --- src/cpu/x86/mtrr/mtrr.c | 19 +++++++++++++++++-- src/include/memrange.h | 13 +++++++++++++ src/lib/memrange.c | 19 +++++++++++++++---- 3 files changed, 45 insertions(+), 6 deletions(-)
diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c index dfb9c94..d85a869 100644 --- a/src/cpu/x86/mtrr/mtrr.c +++ b/src/cpu/x86/mtrr/mtrr.c @@ -30,6 +30,7 @@ #include <bootstate.h> #include <console/console.h> #include <device/device.h> +#include <device/pci_ids.h> #include <cpu/cpu.h> #include <cpu/x86/msr.h> #include <cpu/x86/mtrr.h> @@ -154,6 +155,20 @@ static inline int range_entry_mtrr_type(struct range_entry *r) return range_entry_tag(r) & MTRR_TAG_MASK; }
+static int filter_vga_wrcomb(struct device *dev, struct resource *res) +{ + /* Only handle PCI devices. */ + if (dev->path.type != DEVICE_PATH_PCI) + return 0; + + /* Only handle VGA class devices. */ + if (((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)) + return 0; + + /* Add resource as write-combining in the address space. */ + return 1; +} + static struct memranges *get_physical_address_space(void) { static struct memranges *addr_space; @@ -181,8 +196,8 @@ static struct memranges *get_physical_address_space(void) * resources are appropriate for this MTRR type. */ match = IORESOURCE_PREFETCH; mask |= match; - memranges_add_resources(addr_space, mask, match, - MTRR_TYPE_WRCOMB); + memranges_add_resources_filter(addr_space, mask, match, MTRR_TYPE_WRCOMB, + filter_vga_wrcomb);
#if CONFIG_CACHE_ROM /* Add a write-protect region covering the ROM size diff --git a/src/include/memrange.h b/src/include/memrange.h index 4f094f5..ba85bef 100644 --- a/src/include/memrange.h +++ b/src/include/memrange.h @@ -94,6 +94,19 @@ void memranges_add_resources(struct memranges *ranges, unsigned long mask, unsigned long match, unsigned long tag);
+/* Add memory resources that match with the corresponding mask and match but + * also provide filter as additional check. The filter will return non-zero + * to add the resource or zero to not add the resource. Each entry will be + * tagged with the provided tag. e.g. To populate all cacheable memory + * resources in the range with a filter: + * memranges_add_resources_filter(range, IORESOURCE_CACHEABLE, + * IORESROUCE_CACHEABLE, my_cacheable_tag, filter); */ +typedef int (*memrange_filter_t)(struct device *dev, struct resource *res); +void memranges_add_resources_filter(struct memranges *ranges, + unsigned long mask, unsigned long match, + unsigned long tag, + memrange_filter_t filter); + /* Fill all address ranges up to limit (exclusive) not covered by an entry by * inserting new entries with the provided tag. */ void memranges_fill_holes_up_to(struct memranges *ranges, diff --git a/src/lib/memrange.c b/src/lib/memrange.c index 7fb6ef7..a85bc01 100644 --- a/src/lib/memrange.c +++ b/src/lib/memrange.c @@ -252,6 +252,7 @@ void memranges_insert(struct memranges *ranges, struct collect_context { struct memranges *ranges; unsigned long tag; + memrange_filter_t filter; };
static void collect_ranges(void *gp, struct device *dev, struct resource *res) @@ -261,12 +262,14 @@ static void collect_ranges(void *gp, struct device *dev, struct resource *res) if (res->size == 0) return;
- memranges_insert(ctx->ranges, res->base, res->size, ctx->tag); + if (ctx->filter == NULL || ctx->filter(dev, res)) + memranges_insert(ctx->ranges, res->base, res->size, ctx->tag); }
-void memranges_add_resources(struct memranges *ranges, - unsigned long mask, unsigned long match, - unsigned long tag) +void memranges_add_resources_filter(struct memranges *ranges, + unsigned long mask, unsigned long match, + unsigned long tag, + memrange_filter_t filter) { struct collect_context context;
@@ -276,9 +279,17 @@ void memranges_add_resources(struct memranges *ranges,
context.ranges = ranges; context.tag = tag; + context.filter = filter; search_global_resources(mask, match, collect_ranges, &context); }
+void memranges_add_resources(struct memranges *ranges, + unsigned long mask, unsigned long match, + unsigned long tag) +{ + memranges_add_resources_filter(ranges, mask, match, tag, NULL); +} + void memranges_init(struct memranges *ranges, unsigned long mask, unsigned long match, unsigned long tag)