From: Kevin Cernekee <cernekee@gmail.com>
To: ralf@linux-mips.org
Cc: linux-mips@linux-mips.org, linux-kernel@vger.kernel.org
Subject: [PATCH] MIPS: Machine check exception in kmap_coherent()
Date: Sat, 5 Sep 2009 14:38:41 -0700 [thread overview]
Message-ID: <197625223d8cb6ec3fc3e7da4501dd65@localhost> (raw)
On an SMP MIPS32 2.6.30 system with cache aliases, I am seeing the
following sequence of events:
1) copy_user_highpage() runs on CPU0, invoking kmap_coherent() to create
a temporary mapping in the fixmap region
2) copy_page() starts on CPU0
3) CPU1 sends CPU0 an IPI asking CPU0 to run
local_r4k_flush_cache_page()
4) CPU0 takes the interrupt, interrupting copy_page()
5) local_r4k_flush_cache_page() on CPU0 calls kmap_coherent() again
6) The second invocation of kmap_coherent() on CPU0 tries to use the
same fixmap virtual address that was being used by copy_user_highpage()
7) CPU0 throws a machine check exception for the TLB address conflict
Here is my proposed fix:
a) kmap_coherent() will maintain a flag for each CPU indicating whether
there is an active mapping (kmap_coherent_inuse)
b) kmap_coherent() will return a NULL address in the unlikely case that
it was called while another mapping was already outstanding
c) local_r4k_flush_cache_page() will check for a NULL return value from
kmap_coherent(), and compensate by using indexed cacheops instead of hit
cacheops
Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
---
arch/mips/mm/c-r4k.c | 25 +++++++++++++++++++------
arch/mips/mm/init.c | 17 +++++++++++++++--
2 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 6721ee2..572fe7e 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -459,7 +459,7 @@ static inline void local_r4k_flush_cache_page(void *args)
struct page *page = pfn_to_page(fcp_args->pfn);
int exec = vma->vm_flags & VM_EXEC;
struct mm_struct *mm = vma->vm_mm;
- int map_coherent = 0;
+ int map_coherent = 0, use_indexed = 0;
pgd_t *pgdp;
pud_t *pudp;
pmd_t *pmdp;
@@ -499,13 +499,23 @@ static inline void local_r4k_flush_cache_page(void *args)
vaddr = kmap_coherent(page, addr);
else
vaddr = kmap_atomic(page, KM_USER0);
- addr = (unsigned long)vaddr;
+
+ if (unlikely(vaddr == NULL))
+ use_indexed = 1;
+ else
+ addr = (unsigned long)vaddr;
}
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
- r4k_blast_dcache_page(addr);
- if (exec && !cpu_icache_snoops_remote_store)
- r4k_blast_scache_page(addr);
+ if (use_indexed) {
+ r4k_blast_dcache_page_indexed(addr);
+ if (exec && !cpu_icache_snoops_remote_store)
+ r4k_blast_scache_page_indexed(addr);
+ } else {
+ r4k_blast_dcache_page(addr);
+ if (exec && !cpu_icache_snoops_remote_store)
+ r4k_blast_scache_page(addr);
+ }
}
if (exec) {
if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) {
@@ -514,7 +524,10 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_context(cpu, mm) != 0)
drop_mmu_context(mm, cpu);
} else
- r4k_blast_icache_page(addr);
+ if (use_indexed)
+ r4k_blast_icache_page_indexed(addr);
+ else
+ r4k_blast_icache_page(addr);
}
if (vaddr) {
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 0e82050..87967cd 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -31,6 +31,7 @@
#include <asm/asm-offsets.h>
#include <asm/bootinfo.h>
#include <asm/cachectl.h>
+#include <asm/cache.h>
#include <asm/cpu.h>
#include <asm/dma.h>
#include <asm/kmap_types.h>
@@ -105,6 +106,8 @@ unsigned long setup_zero_pages(void)
return 1UL << order;
}
+static int kmap_coherent_inuse[NR_CPUS] ____cacheline_aligned_in_smp;
+
#ifdef CONFIG_MIPS_MT_SMTC
static pte_t *kmap_coherent_pte;
static void __init kmap_coherent_init(void)
@@ -125,14 +128,15 @@ void *kmap_coherent(struct page *page, unsigned long addr)
unsigned long vaddr, flags, entrylo;
unsigned long old_ctx;
pte_t pte;
- int tlbidx;
+ int tlbidx, cpu;
BUG_ON(Page_dcache_dirty(page));
inc_preempt_count();
+ cpu = smp_processor_id();
idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
#ifdef CONFIG_MIPS_MT_SMTC
- idx += FIX_N_COLOURS * smp_processor_id();
+ idx += FIX_N_COLOURS * cpu;
#endif
vaddr = __fix_to_virt(FIX_CMAP_END - idx);
pte = mk_pte(page, PAGE_KERNEL);
@@ -143,6 +147,13 @@ void *kmap_coherent(struct page *page, unsigned long addr)
#endif
ENTER_CRITICAL(flags);
+ if (unlikely(kmap_coherent_inuse[cpu] != 0)) {
+ vaddr = 0;
+ dec_preempt_count();
+ goto out;
+ }
+ kmap_coherent_inuse[cpu] = 1;
+
old_ctx = read_c0_entryhi();
write_c0_entryhi(vaddr & (PAGE_MASK << 1));
write_c0_entrylo0(entrylo);
@@ -168,6 +179,7 @@ void *kmap_coherent(struct page *page, unsigned long addr)
#endif
tlbw_use_hazard();
write_c0_entryhi(old_ctx);
+out:
EXIT_CRITICAL(flags);
return (void*) vaddr;
@@ -195,6 +207,7 @@ void kunmap_coherent(void)
write_c0_entryhi(old_ctx);
EXIT_CRITICAL(flags);
#endif
+ kmap_coherent_inuse[smp_processor_id()] = 0;
dec_preempt_count();
preempt_check_resched();
}
--
1.6.3.1
next reply other threads:[~2009-09-06 20:56 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-05 21:38 Kevin Cernekee [this message]
2009-09-07 10:26 ` [PATCH] MIPS: Machine check exception in kmap_coherent() Ralf Baechle
2009-09-07 18:11 ` [PATCHv2] " Kevin Cernekee
2009-09-07 18:28 ` [PATCH] " Kevin Cernekee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=197625223d8cb6ec3fc3e7da4501dd65@localhost \
--to=cernekee@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
--cc=ralf@linux-mips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.