HIGHMEM is broken when working in SMP V6 mode
saeed bishara
saeed.bishara at gmail.com
Mon Jan 24 03:47:36 EST 2011
>> >> I've port 2.6.35 to SMP system that runs in V6 mode, this system
>> >> doesn't support TLB operations broadcasting by hw, so it uses IPI
>> >> messages for that. when enabling DEBUG_LOCKDEP, I got the following
>> >> error message while booting the system from NFS:
>> >
>> > You've bypassed this check:
>> >
>> > if (is_smp() && tlb_ops_need_broadcast()) {
>> > /*
>> > * kmap_high needs to occasionally flush TLB entries,
>> > * however, if the TLB entries need to be broadcast
>> > * we may deadlock:
>> > * kmap_high(irqs off)->flush_all_zero_pkmaps->
>> > * flush_tlb_kernel_range->smp_call_function_many
>> > * (must not be called with irqs off)
>> > */
>> > reason = "without hardware TLB ops broadcasting";
>> > }
>> >
>> > so you lose. There's reasons why such checks are put in. We can not
>> > support SMP and highmem on systems which do not have TLB broadcasting.
>> > That's not because the code doesn't support it, it's because there are
>> > deadlocks which will occur.
>> thanks, I missed that
>> >
>> > The fact is that it is unsafe to send IPIs with IRQs disabled, which
>> > means you can't IPI a TLB operation and wait for it to complete with IRQs
>> > disabled.
>> as I understand it, the lock_kmap() started to disable IRQs in order
>> to support the vivt and vipt caches, but in SMP (at least in my case),
>> the caches are PIPT, so I think I can do the following:
>> 1. undef the ARCH_NEEDS_KMAP_HIGH_GET
>> 2. use page_address instead of kmap_high_get()
>> do you think it will work?
>
> Definitely not. We use kmap_high_get() so that we can ensure that we've
> flushed data out of the PIPT cache for highmem pages. highmem pages
> which are unmapped do not have a valid page_address() but may have PIPT
> cache lines associated with them.
>
> So no, I don't think it'll be safe.
ok, what about the following patch, the idea is to use only the
kmap_high_l1_vipt when doing cache maintenance.
diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h
index feb988a..457998c 100644
--- a/arch/arm/include/asm/highmem.h
+++ b/arch/arm/include/asm/highmem.h
@@ -19,7 +19,9 @@
extern pte_t *pkmap_page_table;
+#ifndef CONFIG_SMP
#define ARCH_NEEDS_KMAP_HIGH_GET
+#endif
extern void *kmap_high(struct page *page);
extern void *kmap_high_get(struct page *page);
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 9e7742f..d22366b 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -459,12 +459,15 @@ static void dma_cache_maint_page(struct page
*page, unsigned long offset,
}
len = PAGE_SIZE - offset;
}
+#ifdef ARCH_NEEDS_KMAP_HIGH_GET
vaddr = kmap_high_get(page);
if (vaddr) {
vaddr += offset;
op(vaddr, len, dir);
kunmap_high(page);
- } else if (cache_is_vipt()) {
+ } else if (cache_is_vipt())
+#endif
+ {
pte_t saved_pte;
vaddr = kmap_high_l1_vipt(page, &saved_pte);
op(vaddr + offset, len, dir);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index c6844cb..7f96b2c 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -161,11 +161,15 @@ void __flush_dcache_page(struct address_space
*mapping, struct page *page)
if (!PageHighMem(page)) {
__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
} else {
- void *addr = kmap_high_get(page);
+ void *addr;
+#ifdef ARCH_NEEDS_KMAP_HIGH_GET
+ addr = kmap_high_get(page);
if (addr) {
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
kunmap_high(page);
- } else if (cache_is_vipt()) {
+ } else if (cache_is_vipt())
+#endif
+ {
pte_t saved_pte;
addr = kmap_high_l1_vipt(page, &saved_pte);
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index 6ab2440..7493a79 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -57,7 +57,11 @@ void *kmap_atomic(struct page *page, enum km_type type)
kmap = NULL;
else
#endif
+#ifdef ARCH_NEEDS_KMAP_HIGH_GET
kmap = kmap_high_get(page);
+#else
+ kmap = NULL;
+#endif
if (kmap)
return kmap;
More information about the linux-arm-kernel
mailing list