CHROMIUM: Work around Intel GPU bug with some physical pages.
authorStéphane Marchesin <marcheu@chromium.org>
Mon, 7 May 2012 21:57:11 +0000 (14:57 -0700)
committerOlof Johansson <olof@lixom.net>
Fri, 1 Jun 2012 06:48:20 +0000 (23:48 -0700)
Some intel GPUs don't like using those physical pages, resulting in
garbage all over the place. We could fix it by adding an e820 region,
but that prevents the machine from booting. We could fix it in i915,
but since the allocation is done by the backing shmem it's not
possible. So we have to do the workaround in shmem.c.

As a side note, if we have that workaround in place, we can probably
reclaim 4 megabytes of memory (twice 2 megs) which are marked
reserved by the bios.

BUG=chromium:120949
TEST=by hand; set mem=450M and play with Chrome OS, corruption is gone.

Signed-off-by: Stéphane Marchesin <marcheu@chromium.org>
Change-Id: I957e125fb280e0b0d6b05a83cc4068df2f05aa0a
Reviewed-on: https://gerrit.chromium.org/gerrit/22054
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Olof Johansson <olofj@chromium.org>
Tested-by: Stéphane Marchesin <marcheu@chromium.org>
Commit-Ready: Stéphane Marchesin <marcheu@chromium.org>

mm/shmem.c

index f99ff3e..9da7550 100644 (file)
@@ -768,6 +768,31 @@ redirty:
        return 0;
 }
 
+/*
+ * Some intel GPUs can't use those pages in the GTT, which results in
+ * graphics corruption. Sadly, it's impossible to prevent usage of those
+ * pages in the intel allocator.
+ *
+ * Instead, we test for those areas here and leak the corresponding pages.
+ *
+ * Some day, when the intel GPU memory is not backed by shmem any more,
+ * we'll be able to come up with a solution which is contained in i915.
+ */
+static bool i915_usable_page(struct page *page)
+{
+       dma_addr_t addr = page_to_phys(page);
+
+       if (unlikely((addr < 1 * 1024 * 1024) ||
+               (addr == 0x20050000) ||
+               (addr == 0x20110000) ||
+               (addr == 0x20130000) ||
+               (addr == 0x20138000) ||
+               (addr == 0x40004000)))
+               return false;
+
+       return true;
+}
+
 #ifdef CONFIG_NUMA
 #ifdef CONFIG_TMPFS
 static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol)
@@ -816,6 +841,7 @@ static struct page *shmem_alloc_page(gfp_t gfp,
                        struct shmem_inode_info *info, pgoff_t index)
 {
        struct vm_area_struct pvma;
+       struct page *page;
 
        /* Create a pseudo vma that just contains the policy */
        pvma.vm_start = 0;
@@ -826,7 +852,11 @@ static struct page *shmem_alloc_page(gfp_t gfp,
        /*
         * alloc_page_vma() will drop the shared policy reference
         */
-       return alloc_page_vma(gfp, &pvma, 0);
+       do {
+               page = alloc_page_vma(gfp, &pvma, 0);
+       } while (!i915_usable_page(page));
+
+       return page;
 }
 #else /* !CONFIG_NUMA */
 #ifdef CONFIG_TMPFS
@@ -844,7 +874,12 @@ static inline struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
 static inline struct page *shmem_alloc_page(gfp_t gfp,
                        struct shmem_inode_info *info, pgoff_t index)
 {
-       return alloc_page(gfp);
+       struct page *page;
+       do {
+               page = alloc_page(gfp);
+       } while (!i915_usable_page(page));
+
+       return page;
 }
 #endif /* CONFIG_NUMA */