Skip to content

Commit

Permalink
ARM: 6639/1: allow highmem on SMP platforms without h/w TLB ops broad…
Browse files Browse the repository at this point in the history
…cast

In commit e616c59, highmem support was
deactivated for SMP platforms without hardware TLB ops broadcast because
usage of kmap_high_get() requires that IRQs be disabled when kmap_lock
is locked which is incompatible with the IPI mechanism used by the
software TLB ops broadcast invoked through flush_all_zero_pkmaps().

The reason for kmap_high_get() is to ensure that the currently kmap'd
page usage count does not decrease to zero while we're using its
existing virtual mapping in an atomic context.  With a VIVT cache this
is essential to do due to cache coherency issues, but with a VIPT cache
this is only an optimization so not to pay the price of establishing a
second mapping if an existing one can be used.  However, on VIPT
platforms without hardware TLB maintenance we can give up on that
optimization in order to be able to use highmem.

From ARMv7 onwards the TLB ops are broadcasted in hardware, so let's
disable ARCH_NEEDS_KMAP_HIGH_GET only when CONFIG_SMP and
CONFIG_CPU_TLB_V6 are defined.

Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Tested-by: Saeed Bishara <saeed.bishara@gmail.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Nicolas Pitre authored and Russell King committed Feb 23, 2011
1 parent c191789 commit aaa5004
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 12 deletions.
29 changes: 27 additions & 2 deletions arch/arm/include/asm/highmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,36 @@

extern pte_t *pkmap_page_table;

extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);

/*
* The reason for kmap_high_get() is to ensure that the currently kmap'd
* page usage count does not decrease to zero while we're using its
* existing virtual mapping in an atomic context. With a VIVT cache this
* is essential to do, but with a VIPT cache this is only an optimization
* so not to pay the price of establishing a second mapping if an existing
* one can be used. However, on platforms without hardware TLB maintenance
* broadcast, we simply cannot use ARCH_NEEDS_KMAP_HIGH_GET at all since
* the locking involved must also disable IRQs which is incompatible with
* the IPI mechanism used by global TLB operations.
*/
#define ARCH_NEEDS_KMAP_HIGH_GET
#if defined(CONFIG_SMP) && defined(CONFIG_CPU_TLB_V6)
#undef ARCH_NEEDS_KMAP_HIGH_GET
#if defined(CONFIG_HIGHMEM) && defined(CONFIG_CPU_CACHE_VIVT)
#error "The sum of features in your kernel config cannot be supported together"
#endif
#endif

extern void *kmap_high(struct page *page);
#ifdef ARCH_NEEDS_KMAP_HIGH_GET
extern void *kmap_high_get(struct page *page);
extern void kunmap_high(struct page *page);
#else
static inline void *kmap_high_get(struct page *page)
{
return NULL;
}
#endif

/*
* The following functions are already defined by <linux/highmem.h>
Expand Down
10 changes: 0 additions & 10 deletions arch/arm/mm/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -827,16 +827,6 @@ static void __init sanity_check_meminfo(void)
* rather difficult.
*/
reason = "with VIPT aliasing cache";
} else 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";
}
if (reason) {
printk(KERN_CRIT "HIGHMEM is not supported %s, ignoring high memory\n",
Expand Down

0 comments on commit aaa5004

Please sign in to comment.