From: Ralf Baechle <ralf@linux-mips.org>
To: Kevin Cernekee <cernekee@gmail.com>
Cc: linux-mips@linux-mips.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] MIPS: Machine check exception in kmap_coherent()
Date: Mon, 7 Sep 2009 12:26:13 +0200 [thread overview]
Message-ID: <20090907102613.GA25295@linux-mips.org> (raw)
In-Reply-To: <197625223d8cb6ec3fc3e7da4501dd65@localhost>
On Sat, Sep 05, 2009 at 02:38:41PM -0700, Kevin Cernekee wrote:
> 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
Nice analysis!
> 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
Too complicated. The fault is happening because the non-SMTC code is trying
to be terribly clever and pre-loading the TLB with a new wired entry. On
SMTC where multiple processors are sharing a single TLB are more careful
approach is needed so the code does a TLB probe and carefully and re-uses
an existing entry, if any. Which happens to be just what we need.
So how about below - only compile tested - patch?
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/mm/init.c | 35 +----------------------------------
1 files changed, 1 insertions(+), 34 deletions(-)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 0e82050..ab11582 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -105,8 +105,8 @@ unsigned long setup_zero_pages(void)
return 1UL << order;
}
-#ifdef CONFIG_MIPS_MT_SMTC
static pte_t *kmap_coherent_pte;
+
static void __init kmap_coherent_init(void)
{
unsigned long vaddr;
@@ -115,9 +115,6 @@ static void __init kmap_coherent_init(void)
vaddr = __fix_to_virt(FIX_CMAP_BEGIN);
kmap_coherent_pte = kmap_get_fixmap_pte(vaddr);
}
-#else
-static inline void kmap_coherent_init(void) {}
-#endif
void *kmap_coherent(struct page *page, unsigned long addr)
{
@@ -131,9 +128,7 @@ void *kmap_coherent(struct page *page, unsigned long addr)
inc_preempt_count();
idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
-#ifdef CONFIG_MIPS_MT_SMTC
idx += FIX_N_COLOURS * smp_processor_id();
-#endif
vaddr = __fix_to_virt(FIX_CMAP_END - idx);
pte = mk_pte(page, PAGE_KERNEL);
#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
@@ -147,7 +142,6 @@ void *kmap_coherent(struct page *page, unsigned long addr)
write_c0_entryhi(vaddr & (PAGE_MASK << 1));
write_c0_entrylo0(entrylo);
write_c0_entrylo1(entrylo);
-#ifdef CONFIG_MIPS_MT_SMTC
set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte);
/* preload TLB instead of local_flush_tlb_one() */
mtc0_tlbw_hazard();
@@ -159,13 +153,6 @@ void *kmap_coherent(struct page *page, unsigned long addr)
tlb_write_random();
else
tlb_write_indexed();
-#else
- tlbidx = read_c0_wired();
- write_c0_wired(tlbidx + 1);
- write_c0_index(tlbidx);
- mtc0_tlbw_hazard();
- tlb_write_indexed();
-#endif
tlbw_use_hazard();
write_c0_entryhi(old_ctx);
EXIT_CRITICAL(flags);
@@ -177,24 +164,6 @@ void *kmap_coherent(struct page *page, unsigned long addr)
void kunmap_coherent(void)
{
-#ifndef CONFIG_MIPS_MT_SMTC
- unsigned int wired;
- unsigned long flags, old_ctx;
-
- ENTER_CRITICAL(flags);
- old_ctx = read_c0_entryhi();
- wired = read_c0_wired() - 1;
- write_c0_wired(wired);
- write_c0_index(wired);
- write_c0_entryhi(UNIQUE_ENTRYHI(wired));
- write_c0_entrylo0(0);
- write_c0_entrylo1(0);
- mtc0_tlbw_hazard();
- tlb_write_indexed();
- tlbw_use_hazard();
- write_c0_entryhi(old_ctx);
- EXIT_CRITICAL(flags);
-#endif
dec_preempt_count();
preempt_check_resched();
}
@@ -260,7 +229,6 @@ void copy_from_user_page(struct vm_area_struct *vma,
void __init fixrange_init(unsigned long start, unsigned long end,
pgd_t *pgd_base)
{
-#if defined(CONFIG_HIGHMEM) || defined(CONFIG_MIPS_MT_SMTC)
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
@@ -290,7 +258,6 @@ void __init fixrange_init(unsigned long start, unsigned long end,
}
j = 0;
}
-#endif
}
#ifndef CONFIG_NEED_MULTIPLE_NODES
next prev parent reply other threads:[~2009-09-07 10:25 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-05 21:38 [PATCH] MIPS: Machine check exception in kmap_coherent() Kevin Cernekee
2009-09-07 10:26 ` Ralf Baechle [this message]
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=20090907102613.GA25295@linux-mips.org \
--to=ralf@linux-mips.org \
--cc=cernekee@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@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.