lkml.org 
[lkml]   [2008]   [Feb]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] Fix left over EFI cache mapping problems
    Fix left over EFI cache mapping problems

    [History: this was originally part of a larger patch that got
    partially added earlier. This patch fixes the left-over bugs
    and also fixes another bug I noticed while revising this]

    cpa/set_memory_* does not properly support ioremap or fixmap
    (efi_ioremap on 64bit returns fixmap) addresses. In particular
    it will not correctly change the alias in the direct mapping
    and then cause illegal cache attribute aliases.

    So using it for efi_ioremap is wrong at the current time
    (it might be possible to fix cpa in the future to handle
    this correctly, but that requires much more work is probably not i
    appropiate for .25)

    Fix efi_ioremap() instead to directly set the correct caching
    attributes and then set the direct mapping manually.

    There was also another problem I noticed: the previous call to
    set_memory_uc() passed in bytes as size, but set_memory_*
    requires pages. So it would always set far more memory
    to uncached than really needed. Fixed that one too.
    [This problem was not fixed in the earlier patchkit, but is now]

    I also commented a few more potential (but likely not urgent)
    corner cases.

    Requires the generic ioremap attribute fix I sent earlier
    to work correctly on 32bit.

    Cc: ying.huang@intel.com

    Signed-off-by: Andi Kleen <ak@suse.de>

    ---
    arch/x86/kernel/efi.c | 14 ++++++++------
    arch/x86/kernel/efi_64.c | 6 ++++--
    include/asm-x86/efi.h | 5 +++--
    3 files changed, 15 insertions(+), 10 deletions(-)

    Index: linux/arch/x86/kernel/efi.c
    ===================================================================
    --- linux.orig/arch/x86/kernel/efi.c
    +++ linux/arch/x86/kernel/efi.c
    @@ -413,17 +413,31 @@ void __init efi_enter_virtual_mode(void)

    efi.systab = NULL;
    for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
    + int cached;
    + unsigned numpages;
    +
    md = p;
    if (!(md->attribute & EFI_MEMORY_RUNTIME))
    continue;

    + /*
    + * RED-PEN The spec (and ia64) has a lot more memory
    + * attribute flags should we handle those too?
    + */
    + cached = !!(md->attribute & EFI_MEMORY_WB);
    size = md->num_pages << EFI_PAGE_SHIFT;
    end = md->phys_addr + size;
    + numpages = ALIGN(size, PAGE_SIZE) >> PAGE_SHIFT;

    - if ((end >> PAGE_SHIFT) <= max_pfn_mapped)
    + /* RED-PEN does not handle overlapping */
    + if ((end >> PAGE_SHIFT) <= max_pfn_mapped) {
    va = __va(md->phys_addr);
    - else
    - va = efi_ioremap(md->phys_addr, size);
    + /* RED-PEN someone else could UCed it. */
    + if (!cached)
    + set_memory_uc((unsigned long)va, numpages);
    + } else {
    + va = efi_ioremap(md->phys_addr, size, cached);
    + }

    md->virt_addr = (u64) (unsigned long) va;

    @@ -433,9 +447,6 @@ void __init efi_enter_virtual_mode(void)
    continue;
    }

    - if (!(md->attribute & EFI_MEMORY_WB))
    - set_memory_uc(md->virt_addr, size);
    -
    systab = (u64) (unsigned long) efi_phys.systab;
    if (md->phys_addr <= systab && systab < end) {
    systab += md->virt_addr - md->phys_addr;
    Index: linux/arch/x86/kernel/efi_64.c
    ===================================================================
    --- linux.orig/arch/x86/kernel/efi_64.c
    +++ linux/arch/x86/kernel/efi_64.c
    @@ -103,7 +103,8 @@ void __init efi_reserve_bootmem(void)
    memmap.nr_map * memmap.desc_size);
    }

    -void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size)
    +void __iomem * __init efi_ioremap(unsigned long phys_addr, unsigned long size,
    + int cache)
    {
    static unsigned pages_mapped;
    unsigned i, pages;
    @@ -118,7 +119,8 @@ void __iomem * __init efi_ioremap(unsign

    for (i = 0; i < pages; i++) {
    __set_fixmap(FIX_EFI_IO_MAP_FIRST_PAGE - pages_mapped,
    - phys_addr, PAGE_KERNEL);
    + phys_addr,
    + cache ? PAGE_KERNEL : PAGE_KERNEL_NOCACHE);
    phys_addr += PAGE_SIZE;
    pages_mapped++;
    }
    Index: linux/include/asm-x86/efi.h
    ===================================================================
    --- linux.orig/include/asm-x86/efi.h
    +++ linux/include/asm-x86/efi.h
    @@ -33,7 +33,8 @@ extern unsigned long asmlinkage efi_call
    #define efi_call_virt6(f, a1, a2, a3, a4, a5, a6) \
    efi_call_virt(f, a1, a2, a3, a4, a5, a6)

    -#define efi_ioremap(addr, size) ioremap_cache(addr, size)
    +#define efi_ioremap(addr, size, cache) \
    + (cache ? ioremap_cache(addr, size) : ioremap_nocache(addr, size))

    #else /* !CONFIG_X86_32 */

    @@ -86,7 +87,7 @@ extern u64 efi_call6(void *fp, u64 arg1,
    efi_call6((void *)(efi.systab->runtime->f), (u64)(a1), (u64)(a2), \
    (u64)(a3), (u64)(a4), (u64)(a5), (u64)(a6))

    -extern void *efi_ioremap(unsigned long addr, unsigned long size);
    +extern void *efi_ioremap(unsigned long addr, unsigned long size, int cache);

    #endif /* CONFIG_X86_32 */


    \
     
     \ /
      Last update: 2008-02-14 14:15    [W:2.898 / U:0.232 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site