* [PATCH V2 0/3] HIGHMEM and cache flush fixes.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
This patchset fixes HIGHMEM and utilizes kmap coloring support. The
other two patches fix some cache flushing corner cases.
Changes from V1:
- Rebased against upstream 3.19-rc4 tag.
Leonid Yegoshin (3):
MIPS: Fix cache flushing for swap pages with non-DMA I/O.
MIPS: Highmem: Fixes for cache aliasing and color.
MIPS: Fix I-cache flushing for kmap'd pages.
arch/mips/Kconfig | 1 +
arch/mips/include/asm/cacheflush.h | 3 +-
arch/mips/include/asm/cpu-features.h | 6 ++
arch/mips/include/asm/fixmap.h | 18 +++++-
arch/mips/include/asm/highmem.h | 33 +++++++++++
arch/mips/include/asm/page.h | 5 +-
arch/mips/include/asm/pgtable.h | 5 ++
arch/mips/mm/c-r4k.c | 44 ++++++++++++--
arch/mips/mm/cache.c | 108 ++++++++++++++++++++++------------
arch/mips/mm/highmem.c | 43 +++++---------
arch/mips/mm/init.c | 35 ++++++-----
arch/mips/mm/sc-mips.c | 1 +
12 files changed, 210 insertions(+), 92 deletions(-)
--
1.7.10.4
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH V2 0/3] HIGHMEM and cache flush fixes.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
This patchset fixes HIGHMEM and utilizes kmap coloring support. The
other two patches fix some cache flushing corner cases.
Changes from V1:
- Rebased against upstream 3.19-rc4 tag.
Leonid Yegoshin (3):
MIPS: Fix cache flushing for swap pages with non-DMA I/O.
MIPS: Highmem: Fixes for cache aliasing and color.
MIPS: Fix I-cache flushing for kmap'd pages.
arch/mips/Kconfig | 1 +
arch/mips/include/asm/cacheflush.h | 3 +-
arch/mips/include/asm/cpu-features.h | 6 ++
arch/mips/include/asm/fixmap.h | 18 +++++-
arch/mips/include/asm/highmem.h | 33 +++++++++++
arch/mips/include/asm/page.h | 5 +-
arch/mips/include/asm/pgtable.h | 5 ++
arch/mips/mm/c-r4k.c | 44 ++++++++++++--
arch/mips/mm/cache.c | 108 ++++++++++++++++++++++------------
arch/mips/mm/highmem.c | 43 +++++---------
arch/mips/mm/init.c | 35 ++++++-----
arch/mips/mm/sc-mips.c | 1 +
12 files changed, 210 insertions(+), 92 deletions(-)
--
1.7.10.4
^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Flush the D-cache before the page is given to a process
as an executable (I-cache) page when the backing store
is non-DMA I/O.
Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
---
arch/mips/include/asm/cacheflush.h | 3 ++-
arch/mips/include/asm/cpu-features.h | 3 +++
arch/mips/include/asm/page.h | 5 +++-
arch/mips/include/asm/pgtable.h | 5 ++++
arch/mips/mm/c-r4k.c | 19 +++++++++++++-
arch/mips/mm/cache.c | 46 +++++++++++++++++-----------------
arch/mips/mm/init.c | 23 +++++++++++------
arch/mips/mm/sc-mips.c | 1 +
8 files changed, 72 insertions(+), 33 deletions(-)
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
index e08381a..3a4582a 100644
--- a/arch/mips/include/asm/cacheflush.h
+++ b/arch/mips/include/asm/cacheflush.h
@@ -123,7 +123,8 @@ static inline void kunmap_noncoherent(void)
#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
static inline void flush_kernel_dcache_page(struct page *page)
{
- BUG_ON(cpu_has_dc_aliases && PageHighMem(page));
+ if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
+ __flush_dcache_page(page);
}
/*
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 0d8208d..25ababd 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -142,6 +142,9 @@
#ifndef cpu_has_vtag_icache
#define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG)
#endif
+#ifndef cpu_has_vtag_dcache
+#define cpu_has_vtag_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_VTAG)
+#endif
#ifndef cpu_has_dc_aliases
#define cpu_has_dc_aliases (cpu_data[0].dcache.flags & MIPS_CACHE_ALIASES)
#endif
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 154b70a..fc7ab98 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -95,13 +95,16 @@ static inline unsigned long pages_do_alias(unsigned long addr1,
struct page;
+#include <asm/cpu-features.h>
+
static inline void clear_user_page(void *addr, unsigned long vaddr,
struct page *page)
{
extern void (*flush_data_cache_page)(unsigned long addr);
clear_page(addr);
- if (pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK))
+ if (cpu_has_vtag_dcache || (cpu_has_dc_aliases &&
+ pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK)))
flush_data_cache_page((unsigned long)addr);
}
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 845016d..92a91bb 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -154,6 +154,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
}
}
}
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
@@ -192,6 +193,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
}
#endif
}
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
@@ -409,12 +411,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
extern void __update_tlb(struct vm_area_struct *vma, unsigned long address,
pte_t pte);
+extern void __update_cache(struct vm_area_struct *vma, unsigned long address,
+ pte_t pte);
static inline void update_mmu_cache(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
pte_t pte = *ptep;
__update_tlb(vma, address, pte);
+ __update_cache(vma, address, pte);
}
static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 3f80596..3bb0d06 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -484,8 +484,11 @@ static inline void local_r4k_flush_cache_range(void * args)
return;
r4k_blast_dcache();
- if (exec)
+ if (exec) {
+ if (!cpu_has_ic_fills_f_dc)
+ wmb();
r4k_blast_icache();
+ }
}
static void r4k_flush_cache_range(struct vm_area_struct *vma,
@@ -570,6 +573,14 @@ static inline void local_r4k_flush_cache_page(void *args)
if (!(pte_present(*ptep)))
return;
+ /*
+ * If this page is not destined to be executable and the
+ * data cache does not have aliases, all of the mapping
+ * below can be skipped.
+ */
+ if (!exec && !cpu_has_dc_aliases)
+ return;
+
if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID))
vaddr = NULL;
else {
@@ -589,6 +600,8 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
vaddr ? r4k_blast_dcache_page(addr) :
r4k_blast_dcache_user_page(addr);
+ if (exec && !cpu_has_ic_fills_f_dc)
+ wmb();
if (exec && !cpu_icache_snoops_remote_store)
r4k_blast_scache_page(addr);
}
@@ -621,6 +634,8 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
args.pfn = pfn;
r4k_on_each_cpu(local_r4k_flush_cache_page, &args);
+ if (cpu_has_dc_aliases)
+ ClearPageDcacheDirty(pfn_to_page(pfn));
}
static inline void local_r4k_flush_data_cache_page(void * addr)
@@ -652,6 +667,8 @@ static inline void local_r4k_flush_icache_range(unsigned long start, unsigned lo
}
}
+ wmb();
+
if (end - start > icache_size)
r4k_blast_icache();
else {
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 7e3ea77..99db9e8 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -19,6 +19,7 @@
#include <asm/processor.h>
#include <asm/cpu.h>
#include <asm/cpu-features.h>
+#include <linux/highmem.h>
/* Cache operations. */
void (*flush_cache_all)(void);
@@ -105,48 +106,47 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr)
{
unsigned long addr = (unsigned long) page_address(page);
- if (pages_do_alias(addr, vmaddr)) {
+ if (pages_do_alias(addr, vmaddr & PAGE_MASK)) {
if (page_mapped(page) && !Page_dcache_dirty(page)) {
void *kaddr;
kaddr = kmap_coherent(page, vmaddr);
flush_data_cache_page((unsigned long)kaddr);
kunmap_coherent();
- } else
- flush_data_cache_page(addr);
+ } else {
+ void *kaddr;
+
+ kaddr = kmap_atomic(page);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_atomic(kaddr);
+ ClearPageDcacheDirty(page);
+ }
}
}
EXPORT_SYMBOL(__flush_anon_page);
-static void mips_flush_dcache_from_pte(pte_t pteval, unsigned long address)
+void __update_cache(struct vm_area_struct *vma, unsigned long address,
+ pte_t pte)
{
struct page *page;
- unsigned long pfn = pte_pfn(pteval);
+ unsigned long pfn = pte_pfn(pte);
+ int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
- if (unlikely(!pfn_valid(pfn)))
+ if (unlikely(!pfn_valid(pfn))) {
+ wmb();
return;
-
+ }
page = pfn_to_page(pfn);
- if (page_mapping(page) && Page_dcache_dirty(page)) {
+ if (page_mapped(page) && Page_dcache_dirty(page)) {
unsigned long page_addr = (unsigned long) page_address(page);
-
- if (!cpu_has_ic_fills_f_dc ||
- pages_do_alias(page_addr, address & PAGE_MASK))
+ if (exec || (cpu_has_dc_aliases &&
+ pages_do_alias(page_addr, address & PAGE_MASK))) {
flush_data_cache_page(page_addr);
- ClearPageDcacheDirty(page);
+ ClearPageDcacheDirty(page);
+ }
}
-}
-
-void set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pteval)
-{
- if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) {
- if (pte_present(pteval))
- mips_flush_dcache_from_pte(pteval, addr);
- }
-
- set_pte(ptep, pteval);
+ wmb(); /* finish any outstanding arch cache flushes before ret to user */
}
unsigned long _page_cachable_default;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 448cde3..597bf7f 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -165,9 +165,15 @@ void copy_user_highpage(struct page *to, struct page *from,
copy_page(vto, vfrom);
kunmap_atomic(vfrom);
}
- if ((!cpu_has_ic_fills_f_dc) ||
- pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
+ if (cpu_has_dc_aliases)
+ SetPageDcacheDirty(to);
+ if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+ cpu_has_vtag_dcache || (cpu_has_dc_aliases &&
+ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))) {
flush_data_cache_page((unsigned long)vto);
+ if (cpu_has_dc_aliases)
+ ClearPageDcacheDirty(to);
+ }
kunmap_atomic(vto);
/* Make sure this page is cleared on other CPU's too before using it */
smp_wmb();
@@ -187,8 +193,14 @@ void copy_to_user_page(struct vm_area_struct *vma,
if (cpu_has_dc_aliases)
SetPageDcacheDirty(page);
}
- if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc)
+ if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+ (Page_dcache_dirty(page) &&
+ pages_do_alias((unsigned long)dst & PAGE_MASK,
+ vaddr & PAGE_MASK))) {
flush_cache_page(vma, vaddr, page_to_pfn(page));
+ if (cpu_has_dc_aliases)
+ ClearPageDcacheDirty(page);
+ }
}
void copy_from_user_page(struct vm_area_struct *vma,
@@ -200,11 +212,8 @@ void copy_from_user_page(struct vm_area_struct *vma,
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(dst, vfrom, len);
kunmap_coherent();
- } else {
+ } else
memcpy(dst, src, len);
- if (cpu_has_dc_aliases)
- SetPageDcacheDirty(page);
- }
}
EXPORT_SYMBOL_GPL(copy_from_user_page);
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 4ceafd1..aeed893 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -24,6 +24,7 @@
*/
static void mips_sc_wback_inv(unsigned long addr, unsigned long size)
{
+ __sync();
blast_scache_range(addr, addr + size);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Flush the D-cache before the page is given to a process
as an executable (I-cache) page when the backing store
is non-DMA I/O.
Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
---
arch/mips/include/asm/cacheflush.h | 3 ++-
arch/mips/include/asm/cpu-features.h | 3 +++
arch/mips/include/asm/page.h | 5 +++-
arch/mips/include/asm/pgtable.h | 5 ++++
arch/mips/mm/c-r4k.c | 19 +++++++++++++-
arch/mips/mm/cache.c | 46 +++++++++++++++++-----------------
arch/mips/mm/init.c | 23 +++++++++++------
arch/mips/mm/sc-mips.c | 1 +
8 files changed, 72 insertions(+), 33 deletions(-)
diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h
index e08381a..3a4582a 100644
--- a/arch/mips/include/asm/cacheflush.h
+++ b/arch/mips/include/asm/cacheflush.h
@@ -123,7 +123,8 @@ static inline void kunmap_noncoherent(void)
#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
static inline void flush_kernel_dcache_page(struct page *page)
{
- BUG_ON(cpu_has_dc_aliases && PageHighMem(page));
+ if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
+ __flush_dcache_page(page);
}
/*
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 0d8208d..25ababd 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -142,6 +142,9 @@
#ifndef cpu_has_vtag_icache
#define cpu_has_vtag_icache (cpu_data[0].icache.flags & MIPS_CACHE_VTAG)
#endif
+#ifndef cpu_has_vtag_dcache
+#define cpu_has_vtag_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_VTAG)
+#endif
#ifndef cpu_has_dc_aliases
#define cpu_has_dc_aliases (cpu_data[0].dcache.flags & MIPS_CACHE_ALIASES)
#endif
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 154b70a..fc7ab98 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -95,13 +95,16 @@ static inline unsigned long pages_do_alias(unsigned long addr1,
struct page;
+#include <asm/cpu-features.h>
+
static inline void clear_user_page(void *addr, unsigned long vaddr,
struct page *page)
{
extern void (*flush_data_cache_page)(unsigned long addr);
clear_page(addr);
- if (pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK))
+ if (cpu_has_vtag_dcache || (cpu_has_dc_aliases &&
+ pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK)))
flush_data_cache_page((unsigned long)addr);
}
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index 845016d..92a91bb 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -154,6 +154,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
}
}
}
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
@@ -192,6 +193,7 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
}
#endif
}
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
@@ -409,12 +411,15 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
extern void __update_tlb(struct vm_area_struct *vma, unsigned long address,
pte_t pte);
+extern void __update_cache(struct vm_area_struct *vma, unsigned long address,
+ pte_t pte);
static inline void update_mmu_cache(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
pte_t pte = *ptep;
__update_tlb(vma, address, pte);
+ __update_cache(vma, address, pte);
}
static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 3f80596..3bb0d06 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -484,8 +484,11 @@ static inline void local_r4k_flush_cache_range(void * args)
return;
r4k_blast_dcache();
- if (exec)
+ if (exec) {
+ if (!cpu_has_ic_fills_f_dc)
+ wmb();
r4k_blast_icache();
+ }
}
static void r4k_flush_cache_range(struct vm_area_struct *vma,
@@ -570,6 +573,14 @@ static inline void local_r4k_flush_cache_page(void *args)
if (!(pte_present(*ptep)))
return;
+ /*
+ * If this page is not destined to be executable and the
+ * data cache does not have aliases, all of the mapping
+ * below can be skipped.
+ */
+ if (!exec && !cpu_has_dc_aliases)
+ return;
+
if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID))
vaddr = NULL;
else {
@@ -589,6 +600,8 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) {
vaddr ? r4k_blast_dcache_page(addr) :
r4k_blast_dcache_user_page(addr);
+ if (exec && !cpu_has_ic_fills_f_dc)
+ wmb();
if (exec && !cpu_icache_snoops_remote_store)
r4k_blast_scache_page(addr);
}
@@ -621,6 +634,8 @@ static void r4k_flush_cache_page(struct vm_area_struct *vma,
args.pfn = pfn;
r4k_on_each_cpu(local_r4k_flush_cache_page, &args);
+ if (cpu_has_dc_aliases)
+ ClearPageDcacheDirty(pfn_to_page(pfn));
}
static inline void local_r4k_flush_data_cache_page(void * addr)
@@ -652,6 +667,8 @@ static inline void local_r4k_flush_icache_range(unsigned long start, unsigned lo
}
}
+ wmb();
+
if (end - start > icache_size)
r4k_blast_icache();
else {
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 7e3ea77..99db9e8 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -19,6 +19,7 @@
#include <asm/processor.h>
#include <asm/cpu.h>
#include <asm/cpu-features.h>
+#include <linux/highmem.h>
/* Cache operations. */
void (*flush_cache_all)(void);
@@ -105,48 +106,47 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr)
{
unsigned long addr = (unsigned long) page_address(page);
- if (pages_do_alias(addr, vmaddr)) {
+ if (pages_do_alias(addr, vmaddr & PAGE_MASK)) {
if (page_mapped(page) && !Page_dcache_dirty(page)) {
void *kaddr;
kaddr = kmap_coherent(page, vmaddr);
flush_data_cache_page((unsigned long)kaddr);
kunmap_coherent();
- } else
- flush_data_cache_page(addr);
+ } else {
+ void *kaddr;
+
+ kaddr = kmap_atomic(page);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_atomic(kaddr);
+ ClearPageDcacheDirty(page);
+ }
}
}
EXPORT_SYMBOL(__flush_anon_page);
-static void mips_flush_dcache_from_pte(pte_t pteval, unsigned long address)
+void __update_cache(struct vm_area_struct *vma, unsigned long address,
+ pte_t pte)
{
struct page *page;
- unsigned long pfn = pte_pfn(pteval);
+ unsigned long pfn = pte_pfn(pte);
+ int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
- if (unlikely(!pfn_valid(pfn)))
+ if (unlikely(!pfn_valid(pfn))) {
+ wmb();
return;
-
+ }
page = pfn_to_page(pfn);
- if (page_mapping(page) && Page_dcache_dirty(page)) {
+ if (page_mapped(page) && Page_dcache_dirty(page)) {
unsigned long page_addr = (unsigned long) page_address(page);
-
- if (!cpu_has_ic_fills_f_dc ||
- pages_do_alias(page_addr, address & PAGE_MASK))
+ if (exec || (cpu_has_dc_aliases &&
+ pages_do_alias(page_addr, address & PAGE_MASK))) {
flush_data_cache_page(page_addr);
- ClearPageDcacheDirty(page);
+ ClearPageDcacheDirty(page);
+ }
}
-}
-
-void set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pteval)
-{
- if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) {
- if (pte_present(pteval))
- mips_flush_dcache_from_pte(pteval, addr);
- }
-
- set_pte(ptep, pteval);
+ wmb(); /* finish any outstanding arch cache flushes before ret to user */
}
unsigned long _page_cachable_default;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 448cde3..597bf7f 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -165,9 +165,15 @@ void copy_user_highpage(struct page *to, struct page *from,
copy_page(vto, vfrom);
kunmap_atomic(vfrom);
}
- if ((!cpu_has_ic_fills_f_dc) ||
- pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
+ if (cpu_has_dc_aliases)
+ SetPageDcacheDirty(to);
+ if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+ cpu_has_vtag_dcache || (cpu_has_dc_aliases &&
+ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))) {
flush_data_cache_page((unsigned long)vto);
+ if (cpu_has_dc_aliases)
+ ClearPageDcacheDirty(to);
+ }
kunmap_atomic(vto);
/* Make sure this page is cleared on other CPU's too before using it */
smp_wmb();
@@ -187,8 +193,14 @@ void copy_to_user_page(struct vm_area_struct *vma,
if (cpu_has_dc_aliases)
SetPageDcacheDirty(page);
}
- if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc)
+ if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) ||
+ (Page_dcache_dirty(page) &&
+ pages_do_alias((unsigned long)dst & PAGE_MASK,
+ vaddr & PAGE_MASK))) {
flush_cache_page(vma, vaddr, page_to_pfn(page));
+ if (cpu_has_dc_aliases)
+ ClearPageDcacheDirty(page);
+ }
}
void copy_from_user_page(struct vm_area_struct *vma,
@@ -200,11 +212,8 @@ void copy_from_user_page(struct vm_area_struct *vma,
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
memcpy(dst, vfrom, len);
kunmap_coherent();
- } else {
+ } else
memcpy(dst, src, len);
- if (cpu_has_dc_aliases)
- SetPageDcacheDirty(page);
- }
}
EXPORT_SYMBOL_GPL(copy_from_user_page);
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 4ceafd1..aeed893 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -24,6 +24,7 @@
*/
static void mips_sc_wback_inv(unsigned long addr, unsigned long size)
{
+ __sync();
blast_scache_range(addr, addr + size);
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH V2 2/3] MIPS: Highmem: Fixes for cache aliasing and color.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Make HIGHMEM kmap cache coloring aware and fix some corner
cases for cache aliasing.
Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
---
arch/mips/Kconfig | 1 +
arch/mips/include/asm/fixmap.h | 18 ++++++++-
arch/mips/include/asm/highmem.h | 33 +++++++++++++++
arch/mips/mm/c-r4k.c | 8 ++++
arch/mips/mm/cache.c | 84 ++++++++++++++++++++++++++-------------
arch/mips/mm/highmem.c | 43 ++++++++------------
arch/mips/mm/init.c | 10 +----
7 files changed, 132 insertions(+), 65 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8523db5..da6c43f 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -394,6 +394,7 @@ config MIPS_MALTA
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_ZBOOT
+ select SYS_SUPPORTS_HIGHMEM
help
This enables support for the MIPS Technologies Malta evaluation
board.
diff --git a/arch/mips/include/asm/fixmap.h b/arch/mips/include/asm/fixmap.h
index 6842ffa..f7733a0 100644
--- a/arch/mips/include/asm/fixmap.h
+++ b/arch/mips/include/asm/fixmap.h
@@ -46,13 +46,27 @@
* fix-mapped?
*/
enum fixed_addresses {
+
+/*
+ * Must be <=8 but, last_pkmap_nr_arr[] is still initialized to
+ * 8 elements. Keep the total L1 size <= 512KB with 4-ways.
+ */
+#ifdef CONFIG_PAGE_SIZE_64KB
+#define FIX_N_COLOURS 2
+#endif
+#ifdef CONFIG_PAGE_SIZE_32KB
+#define FIX_N_COLOURS 4
+#endif
+#ifndef FIX_N_COLOURS
#define FIX_N_COLOURS 8
+#endif
+
FIX_CMAP_BEGIN,
- FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * 2),
+ FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS * 2),
#ifdef CONFIG_HIGHMEM
/* reserved pte's for temporary kernel mappings */
FIX_KMAP_BEGIN = FIX_CMAP_END + 1,
- FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+ FIX_KMAP_END = FIX_KMAP_BEGIN+(8*NR_CPUS*FIX_N_COLOURS)-1,
#endif
__end_of_fixed_addresses
};
diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h
index 572e63e..af6180f 100644
--- a/arch/mips/include/asm/highmem.h
+++ b/arch/mips/include/asm/highmem.h
@@ -36,11 +36,44 @@ extern pte_t *pkmap_page_table;
* easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM.
*/
+
+/* 8 colors pages are here */
+#ifdef CONFIG_PAGE_SIZE_4KB
+#define LAST_PKMAP 4096
+#endif
+#ifdef CONFIG_PAGE_SIZE_8KB
+#define LAST_PKMAP 2048
+#endif
+#ifdef CONFIG_PAGE_SIZE_16KB
+#define LAST_PKMAP 1024
+#endif
+
+/* 32KB and 64KB pages should have 4 and 2 colors to keep space under control */
+#ifndef LAST_PKMAP
#define LAST_PKMAP 1024
+#endif
+
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+#define get_pkmap_color(pg) (((unsigned long)lowmem_page_address(pg) >> PAGE_SHIFT) & (FIX_N_COLOURS-1))
+#define get_last_pkmap_nr(cl) (last_pkmap_nr_arr[cl])
+#define get_next_pkmap_nr(cl) (last_pkmap_nr_arr[cl] = \
+ ((get_last_pkmap_nr(cl) + FIX_N_COLOURS) & LAST_PKMAP_MASK))
+#define no_more_pkmaps(p,cl) (p < FIX_N_COLOURS)
+#define get_pkmap_entries_count(c) (c - FIX_N_COLOURS)
+
+static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color)
+{
+ static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);
+
+ return &pkmap_map_wait;
+}
+
+extern unsigned int last_pkmap_nr_arr[];
+
+
extern void * kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 3bb0d06..779dcfa 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1289,6 +1289,14 @@ static void probe_pcache(void)
c->dcache.flags |= MIPS_CACHE_ALIASES;
}
+#ifdef CONFIG_HIGHMEM
+ if (((c->dcache.flags & MIPS_CACHE_ALIASES) &&
+ ((c->dcache.waysize / PAGE_SIZE) > FIX_N_COLOURS)) ||
+ ((c->icache.flags & MIPS_CACHE_ALIASES) &&
+ ((c->icache.waysize / PAGE_SIZE) > FIX_N_COLOURS)))
+ panic("PAGE_SIZE*WAYS too small for L1 size, too many colors");
+#endif
+
switch (current_cpu_type()) {
case CPU_20KC:
/*
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 99db9e8..49496a4 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -81,12 +81,9 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
void __flush_dcache_page(struct page *page)
{
- struct address_space *mapping = page_mapping(page);
- unsigned long addr;
+ void *addr;
- if (PageHighMem(page))
- return;
- if (mapping && !mapping_mapped(mapping)) {
+ if (page_mapping(page) && !page_mapped(page)) {
SetPageDcacheDirty(page);
return;
}
@@ -96,30 +93,54 @@ void __flush_dcache_page(struct page *page)
* case is for exec env/arg pages and those are %99 certainly going to
* get faulted into the tlb (and thus flushed) anyways.
*/
- addr = (unsigned long) page_address(page);
- flush_data_cache_page(addr);
+ if (PageHighMem(page)) {
+ addr = kmap_atomic(page);
+ flush_data_cache_page((unsigned long)addr);
+ kunmap_atomic(addr);
+ } else {
+ addr = (void *) page_address(page);
+ flush_data_cache_page((unsigned long)addr);
+ }
+ ClearPageDcacheDirty(page);
}
EXPORT_SYMBOL(__flush_dcache_page);
void __flush_anon_page(struct page *page, unsigned long vmaddr)
{
- unsigned long addr = (unsigned long) page_address(page);
-
- if (pages_do_alias(addr, vmaddr & PAGE_MASK)) {
- if (page_mapped(page) && !Page_dcache_dirty(page)) {
- void *kaddr;
-
- kaddr = kmap_coherent(page, vmaddr);
- flush_data_cache_page((unsigned long)kaddr);
- kunmap_coherent();
- } else {
- void *kaddr;
-
- kaddr = kmap_atomic(page);
- flush_data_cache_page((unsigned long)kaddr);
- kunmap_atomic(kaddr);
- ClearPageDcacheDirty(page);
+ if (!PageHighMem(page)) {
+ unsigned long addr = (unsigned long) page_address(page);
+
+ if (pages_do_alias(addr, vmaddr & PAGE_MASK)) {
+ if (page_mapped(page) && !Page_dcache_dirty(page)) {
+ void *kaddr;
+
+ kaddr = kmap_coherent(page, vmaddr);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_coherent();
+ } else {
+ flush_data_cache_page(addr);
+ ClearPageDcacheDirty(page);
+ }
+ }
+ } else {
+ void *laddr = lowmem_page_address(page);
+
+ if (pages_do_alias((unsigned long)laddr, vmaddr & PAGE_MASK)) {
+ if (page_mapped(page) && !Page_dcache_dirty(page)) {
+ void *kaddr;
+
+ kaddr = kmap_coherent(page, vmaddr);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_coherent();
+ } else {
+ void *kaddr;
+
+ kaddr = kmap_atomic(page);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_atomic(kaddr);
+ ClearPageDcacheDirty(page);
+ }
}
}
}
@@ -130,21 +151,30 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address,
pte_t pte)
{
struct page *page;
- unsigned long pfn = pte_pfn(pte);
+ unsigned long pfn, addr;
int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
+ pfn = pte_pfn(pte);
if (unlikely(!pfn_valid(pfn))) {
wmb();
return;
}
page = pfn_to_page(pfn);
if (page_mapped(page) && Page_dcache_dirty(page)) {
- unsigned long page_addr = (unsigned long) page_address(page);
+ void *kaddr = NULL;
+ if (PageHighMem(page)) {
+ addr = (unsigned long)kmap_atomic(page);
+ kaddr = (void *)addr;
+ } else
+ addr = (unsigned long) page_address(page);
if (exec || (cpu_has_dc_aliases &&
- pages_do_alias(page_addr, address & PAGE_MASK))) {
- flush_data_cache_page(page_addr);
+ pages_do_alias(addr, address & PAGE_MASK))) {
+ flush_data_cache_page(addr);
ClearPageDcacheDirty(page);
}
+
+ if (kaddr)
+ kunmap_atomic((void *)kaddr);
}
wmb(); /* finish any outstanding arch cache flushes before ret to user */
}
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index da815d2..10fc041 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -9,6 +9,7 @@
static pte_t *kmap_pte;
unsigned long highstart_pfn, highend_pfn;
+unsigned int last_pkmap_nr_arr[FIX_N_COLOURS] = { 0, 1, 2, 3, 4, 5, 6, 7 };
void *kmap(struct page *page)
{
@@ -53,8 +54,12 @@ void *kmap_atomic(struct page *page)
return page_address(page);
type = kmap_atomic_idx_push();
- idx = type + KM_TYPE_NR*smp_processor_id();
- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+
+ idx = (((unsigned long)lowmem_page_address(page)) >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
+ idx = (FIX_N_COLOURS - idx);
+ idx = idx + FIX_N_COLOURS * (smp_processor_id() + NR_CPUS * type);
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN - 1 + idx); /* actually - FIX_CMAP_END */
+
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(!pte_none(*(kmap_pte - idx)));
#endif
@@ -75,12 +80,16 @@ void __kunmap_atomic(void *kvaddr)
return;
}
- type = kmap_atomic_idx();
#ifdef CONFIG_DEBUG_HIGHMEM
{
- int idx = type + KM_TYPE_NR * smp_processor_id();
+ int idx;
+ type = kmap_atomic_idx();
- BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+ idx = ((unsigned long)kvaddr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
+ idx = (FIX_N_COLOURS - idx);
+ idx = idx + FIX_N_COLOURS * (smp_processor_id() + NR_CPUS * type);
+
+ BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN -1 + idx));
/*
* force other mappings to Oops if they'll try to access
@@ -95,26 +104,6 @@ void __kunmap_atomic(void *kvaddr)
}
EXPORT_SYMBOL(__kunmap_atomic);
-/*
- * This is the same as kmap_atomic() but can map memory that doesn't
- * have a struct page associated with it.
- */
-void *kmap_atomic_pfn(unsigned long pfn)
-{
- unsigned long vaddr;
- int idx, type;
-
- pagefault_disable();
-
- type = kmap_atomic_idx_push();
- idx = type + KM_TYPE_NR*smp_processor_id();
- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
- flush_tlb_one(vaddr);
-
- return (void*) vaddr;
-}
-
struct page *kmap_atomic_to_page(void *ptr)
{
unsigned long idx, vaddr = (unsigned long)ptr;
@@ -124,7 +113,7 @@ struct page *kmap_atomic_to_page(void *ptr)
return virt_to_page(ptr);
idx = virt_to_fix(vaddr);
- pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+ pte = kmap_pte - (idx - FIX_KMAP_BEGIN + 1);
return pte_page(*pte);
}
@@ -133,6 +122,6 @@ void __init kmap_init(void)
unsigned long kmap_vstart;
/* cache the first kmap pte */
- kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN - 1); /* actually - FIX_CMAP_END */
kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
}
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 597bf7f..0dc604a 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -284,7 +284,7 @@ int page_is_ram(unsigned long pagenr)
void __init paging_init(void)
{
unsigned long max_zone_pfns[MAX_NR_ZONES];
- unsigned long lastpfn __maybe_unused;
+ unsigned long lastpfn;
pagetable_init();
@@ -302,14 +302,6 @@ void __init paging_init(void)
#ifdef CONFIG_HIGHMEM
max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
lastpfn = highend_pfn;
-
- if (cpu_has_dc_aliases && max_low_pfn != highend_pfn) {
- printk(KERN_WARNING "This processor doesn't support highmem."
- " %ldk highmem ignored\n",
- (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
- max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
- lastpfn = max_low_pfn;
- }
#endif
free_area_init_nodes(max_zone_pfns);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH V2 2/3] MIPS: Highmem: Fixes for cache aliasing and color.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Make HIGHMEM kmap cache coloring aware and fix some corner
cases for cache aliasing.
Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
---
arch/mips/Kconfig | 1 +
arch/mips/include/asm/fixmap.h | 18 ++++++++-
arch/mips/include/asm/highmem.h | 33 +++++++++++++++
arch/mips/mm/c-r4k.c | 8 ++++
arch/mips/mm/cache.c | 84 ++++++++++++++++++++++++++-------------
arch/mips/mm/highmem.c | 43 ++++++++------------
arch/mips/mm/init.c | 10 +----
7 files changed, 132 insertions(+), 65 deletions(-)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8523db5..da6c43f 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -394,6 +394,7 @@ config MIPS_MALTA
select SYS_SUPPORTS_MULTITHREADING
select SYS_SUPPORTS_SMARTMIPS
select SYS_SUPPORTS_ZBOOT
+ select SYS_SUPPORTS_HIGHMEM
help
This enables support for the MIPS Technologies Malta evaluation
board.
diff --git a/arch/mips/include/asm/fixmap.h b/arch/mips/include/asm/fixmap.h
index 6842ffa..f7733a0 100644
--- a/arch/mips/include/asm/fixmap.h
+++ b/arch/mips/include/asm/fixmap.h
@@ -46,13 +46,27 @@
* fix-mapped?
*/
enum fixed_addresses {
+
+/*
+ * Must be <=8 but, last_pkmap_nr_arr[] is still initialized to
+ * 8 elements. Keep the total L1 size <= 512KB with 4-ways.
+ */
+#ifdef CONFIG_PAGE_SIZE_64KB
+#define FIX_N_COLOURS 2
+#endif
+#ifdef CONFIG_PAGE_SIZE_32KB
+#define FIX_N_COLOURS 4
+#endif
+#ifndef FIX_N_COLOURS
#define FIX_N_COLOURS 8
+#endif
+
FIX_CMAP_BEGIN,
- FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * 2),
+ FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS * 2),
#ifdef CONFIG_HIGHMEM
/* reserved pte's for temporary kernel mappings */
FIX_KMAP_BEGIN = FIX_CMAP_END + 1,
- FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+ FIX_KMAP_END = FIX_KMAP_BEGIN+(8*NR_CPUS*FIX_N_COLOURS)-1,
#endif
__end_of_fixed_addresses
};
diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h
index 572e63e..af6180f 100644
--- a/arch/mips/include/asm/highmem.h
+++ b/arch/mips/include/asm/highmem.h
@@ -36,11 +36,44 @@ extern pte_t *pkmap_page_table;
* easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM.
*/
+
+/* 8 colors pages are here */
+#ifdef CONFIG_PAGE_SIZE_4KB
+#define LAST_PKMAP 4096
+#endif
+#ifdef CONFIG_PAGE_SIZE_8KB
+#define LAST_PKMAP 2048
+#endif
+#ifdef CONFIG_PAGE_SIZE_16KB
+#define LAST_PKMAP 1024
+#endif
+
+/* 32KB and 64KB pages should have 4 and 2 colors to keep space under control */
+#ifndef LAST_PKMAP
#define LAST_PKMAP 1024
+#endif
+
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+#define get_pkmap_color(pg) (((unsigned long)lowmem_page_address(pg) >> PAGE_SHIFT) & (FIX_N_COLOURS-1))
+#define get_last_pkmap_nr(cl) (last_pkmap_nr_arr[cl])
+#define get_next_pkmap_nr(cl) (last_pkmap_nr_arr[cl] = \
+ ((get_last_pkmap_nr(cl) + FIX_N_COLOURS) & LAST_PKMAP_MASK))
+#define no_more_pkmaps(p,cl) (p < FIX_N_COLOURS)
+#define get_pkmap_entries_count(c) (c - FIX_N_COLOURS)
+
+static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color)
+{
+ static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);
+
+ return &pkmap_map_wait;
+}
+
+extern unsigned int last_pkmap_nr_arr[];
+
+
extern void * kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 3bb0d06..779dcfa 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1289,6 +1289,14 @@ static void probe_pcache(void)
c->dcache.flags |= MIPS_CACHE_ALIASES;
}
+#ifdef CONFIG_HIGHMEM
+ if (((c->dcache.flags & MIPS_CACHE_ALIASES) &&
+ ((c->dcache.waysize / PAGE_SIZE) > FIX_N_COLOURS)) ||
+ ((c->icache.flags & MIPS_CACHE_ALIASES) &&
+ ((c->icache.waysize / PAGE_SIZE) > FIX_N_COLOURS)))
+ panic("PAGE_SIZE*WAYS too small for L1 size, too many colors");
+#endif
+
switch (current_cpu_type()) {
case CPU_20KC:
/*
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index 99db9e8..49496a4 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -81,12 +81,9 @@ SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
void __flush_dcache_page(struct page *page)
{
- struct address_space *mapping = page_mapping(page);
- unsigned long addr;
+ void *addr;
- if (PageHighMem(page))
- return;
- if (mapping && !mapping_mapped(mapping)) {
+ if (page_mapping(page) && !page_mapped(page)) {
SetPageDcacheDirty(page);
return;
}
@@ -96,30 +93,54 @@ void __flush_dcache_page(struct page *page)
* case is for exec env/arg pages and those are %99 certainly going to
* get faulted into the tlb (and thus flushed) anyways.
*/
- addr = (unsigned long) page_address(page);
- flush_data_cache_page(addr);
+ if (PageHighMem(page)) {
+ addr = kmap_atomic(page);
+ flush_data_cache_page((unsigned long)addr);
+ kunmap_atomic(addr);
+ } else {
+ addr = (void *) page_address(page);
+ flush_data_cache_page((unsigned long)addr);
+ }
+ ClearPageDcacheDirty(page);
}
EXPORT_SYMBOL(__flush_dcache_page);
void __flush_anon_page(struct page *page, unsigned long vmaddr)
{
- unsigned long addr = (unsigned long) page_address(page);
-
- if (pages_do_alias(addr, vmaddr & PAGE_MASK)) {
- if (page_mapped(page) && !Page_dcache_dirty(page)) {
- void *kaddr;
-
- kaddr = kmap_coherent(page, vmaddr);
- flush_data_cache_page((unsigned long)kaddr);
- kunmap_coherent();
- } else {
- void *kaddr;
-
- kaddr = kmap_atomic(page);
- flush_data_cache_page((unsigned long)kaddr);
- kunmap_atomic(kaddr);
- ClearPageDcacheDirty(page);
+ if (!PageHighMem(page)) {
+ unsigned long addr = (unsigned long) page_address(page);
+
+ if (pages_do_alias(addr, vmaddr & PAGE_MASK)) {
+ if (page_mapped(page) && !Page_dcache_dirty(page)) {
+ void *kaddr;
+
+ kaddr = kmap_coherent(page, vmaddr);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_coherent();
+ } else {
+ flush_data_cache_page(addr);
+ ClearPageDcacheDirty(page);
+ }
+ }
+ } else {
+ void *laddr = lowmem_page_address(page);
+
+ if (pages_do_alias((unsigned long)laddr, vmaddr & PAGE_MASK)) {
+ if (page_mapped(page) && !Page_dcache_dirty(page)) {
+ void *kaddr;
+
+ kaddr = kmap_coherent(page, vmaddr);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_coherent();
+ } else {
+ void *kaddr;
+
+ kaddr = kmap_atomic(page);
+ flush_data_cache_page((unsigned long)kaddr);
+ kunmap_atomic(kaddr);
+ ClearPageDcacheDirty(page);
+ }
}
}
}
@@ -130,21 +151,30 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address,
pte_t pte)
{
struct page *page;
- unsigned long pfn = pte_pfn(pte);
+ unsigned long pfn, addr;
int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
+ pfn = pte_pfn(pte);
if (unlikely(!pfn_valid(pfn))) {
wmb();
return;
}
page = pfn_to_page(pfn);
if (page_mapped(page) && Page_dcache_dirty(page)) {
- unsigned long page_addr = (unsigned long) page_address(page);
+ void *kaddr = NULL;
+ if (PageHighMem(page)) {
+ addr = (unsigned long)kmap_atomic(page);
+ kaddr = (void *)addr;
+ } else
+ addr = (unsigned long) page_address(page);
if (exec || (cpu_has_dc_aliases &&
- pages_do_alias(page_addr, address & PAGE_MASK))) {
- flush_data_cache_page(page_addr);
+ pages_do_alias(addr, address & PAGE_MASK))) {
+ flush_data_cache_page(addr);
ClearPageDcacheDirty(page);
}
+
+ if (kaddr)
+ kunmap_atomic((void *)kaddr);
}
wmb(); /* finish any outstanding arch cache flushes before ret to user */
}
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index da815d2..10fc041 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -9,6 +9,7 @@
static pte_t *kmap_pte;
unsigned long highstart_pfn, highend_pfn;
+unsigned int last_pkmap_nr_arr[FIX_N_COLOURS] = { 0, 1, 2, 3, 4, 5, 6, 7 };
void *kmap(struct page *page)
{
@@ -53,8 +54,12 @@ void *kmap_atomic(struct page *page)
return page_address(page);
type = kmap_atomic_idx_push();
- idx = type + KM_TYPE_NR*smp_processor_id();
- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+
+ idx = (((unsigned long)lowmem_page_address(page)) >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
+ idx = (FIX_N_COLOURS - idx);
+ idx = idx + FIX_N_COLOURS * (smp_processor_id() + NR_CPUS * type);
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN - 1 + idx); /* actually - FIX_CMAP_END */
+
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(!pte_none(*(kmap_pte - idx)));
#endif
@@ -75,12 +80,16 @@ void __kunmap_atomic(void *kvaddr)
return;
}
- type = kmap_atomic_idx();
#ifdef CONFIG_DEBUG_HIGHMEM
{
- int idx = type + KM_TYPE_NR * smp_processor_id();
+ int idx;
+ type = kmap_atomic_idx();
- BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx));
+ idx = ((unsigned long)kvaddr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
+ idx = (FIX_N_COLOURS - idx);
+ idx = idx + FIX_N_COLOURS * (smp_processor_id() + NR_CPUS * type);
+
+ BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN -1 + idx));
/*
* force other mappings to Oops if they'll try to access
@@ -95,26 +104,6 @@ void __kunmap_atomic(void *kvaddr)
}
EXPORT_SYMBOL(__kunmap_atomic);
-/*
- * This is the same as kmap_atomic() but can map memory that doesn't
- * have a struct page associated with it.
- */
-void *kmap_atomic_pfn(unsigned long pfn)
-{
- unsigned long vaddr;
- int idx, type;
-
- pagefault_disable();
-
- type = kmap_atomic_idx_push();
- idx = type + KM_TYPE_NR*smp_processor_id();
- vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL));
- flush_tlb_one(vaddr);
-
- return (void*) vaddr;
-}
-
struct page *kmap_atomic_to_page(void *ptr)
{
unsigned long idx, vaddr = (unsigned long)ptr;
@@ -124,7 +113,7 @@ struct page *kmap_atomic_to_page(void *ptr)
return virt_to_page(ptr);
idx = virt_to_fix(vaddr);
- pte = kmap_pte - (idx - FIX_KMAP_BEGIN);
+ pte = kmap_pte - (idx - FIX_KMAP_BEGIN + 1);
return pte_page(*pte);
}
@@ -133,6 +122,6 @@ void __init kmap_init(void)
unsigned long kmap_vstart;
/* cache the first kmap pte */
- kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN - 1); /* actually - FIX_CMAP_END */
kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
}
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 597bf7f..0dc604a 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -284,7 +284,7 @@ int page_is_ram(unsigned long pagenr)
void __init paging_init(void)
{
unsigned long max_zone_pfns[MAX_NR_ZONES];
- unsigned long lastpfn __maybe_unused;
+ unsigned long lastpfn;
pagetable_init();
@@ -302,14 +302,6 @@ void __init paging_init(void)
#ifdef CONFIG_HIGHMEM
max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
lastpfn = highend_pfn;
-
- if (cpu_has_dc_aliases && max_low_pfn != highend_pfn) {
- printk(KERN_WARNING "This processor doesn't support highmem."
- " %ldk highmem ignored\n",
- (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10));
- max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn;
- lastpfn = max_low_pfn;
- }
#endif
free_area_init_nodes(max_zone_pfns);
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH V2 3/3] MIPS: Fix I-cache flushing for kmap'd pages.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Make the I-cache flush pages while taking into account the
address color by using kmap_coherent() when there is
I-cache aliasing present.
Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
---
arch/mips/include/asm/cpu-features.h | 3 +++
arch/mips/mm/c-r4k.c | 17 ++++++++++++++---
arch/mips/mm/init.c | 2 --
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 25ababd..16b67e9 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -145,6 +145,9 @@
#ifndef cpu_has_vtag_dcache
#define cpu_has_vtag_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_VTAG)
#endif
+#ifndef cpu_has_ic_aliases
+#define cpu_has_ic_aliases (cpu_data[0].icache.flags & MIPS_CACHE_ALIASES)
+#endif
#ifndef cpu_has_dc_aliases
#define cpu_has_dc_aliases (cpu_data[0].dcache.flags & MIPS_CACHE_ALIASES)
#endif
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 779dcfa..3dbc14d 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -552,6 +552,7 @@ static inline void local_r4k_flush_cache_page(void *args)
pmd_t *pmdp;
pte_t *ptep;
void *vaddr;
+ int noflush = 0;
/*
* If ownes no valid ASID yet, cannot possibly have gotten
@@ -611,6 +612,7 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_context(cpu, mm) != 0)
drop_mmu_context(mm, cpu);
+ noflush = 1;
} else
vaddr ? r4k_blast_icache_page(addr) :
r4k_blast_icache_user_page(addr);
@@ -622,6 +624,13 @@ static inline void local_r4k_flush_cache_page(void *args)
else
kunmap_atomic(vaddr);
}
+
+ /* If we have I-cache aliasing, then blast it via coherent page. */
+ if (exec && cpu_has_ic_aliases && !noflush && !map_coherent) {
+ vaddr = kmap_coherent(page, addr);
+ r4k_blast_icache_page((unsigned long)vaddr);
+ kunmap_coherent();
+ }
}
static void r4k_flush_cache_page(struct vm_area_struct *vma,
@@ -1318,10 +1327,12 @@ static void probe_pcache(void)
c->icache.ways = 1;
}
- printk("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n",
- icache_size >> 10,
+ printk("Primary instruction cache %ldkB, %s, %s, %slinesize %d bytes.\n",
+ icache_size >> 10, way_string[c->icache.ways],
c->icache.flags & MIPS_CACHE_VTAG ? "VIVT" : "VIPT",
- way_string[c->icache.ways], c->icache.linesz);
+ (c->icache.flags & MIPS_CACHE_ALIASES) ?
+ "I-cache aliases, " : "",
+ c->icache.linesz);
printk("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n",
dcache_size >> 10, way_string[c->dcache.ways],
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 0dc604a..b1584d6 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -88,8 +88,6 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
pte_t pte;
int tlbidx;
- BUG_ON(Page_dcache_dirty(page));
-
pagefault_disable();
idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
idx += in_interrupt() ? FIX_N_COLOURS : 0;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread
* [PATCH V2 3/3] MIPS: Fix I-cache flushing for kmap'd pages.
@ 2015-02-19 16:17 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-19 16:17 UTC (permalink / raw)
To: IMG-MIPSLinuxKerneldevelopers, linux-mips
From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Make the I-cache flush pages while taking into account the
address color by using kmap_coherent() when there is
I-cache aliasing present.
Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
---
arch/mips/include/asm/cpu-features.h | 3 +++
arch/mips/mm/c-r4k.c | 17 ++++++++++++++---
arch/mips/mm/init.c | 2 --
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index 25ababd..16b67e9 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -145,6 +145,9 @@
#ifndef cpu_has_vtag_dcache
#define cpu_has_vtag_dcache (cpu_data[0].dcache.flags & MIPS_CACHE_VTAG)
#endif
+#ifndef cpu_has_ic_aliases
+#define cpu_has_ic_aliases (cpu_data[0].icache.flags & MIPS_CACHE_ALIASES)
+#endif
#ifndef cpu_has_dc_aliases
#define cpu_has_dc_aliases (cpu_data[0].dcache.flags & MIPS_CACHE_ALIASES)
#endif
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 779dcfa..3dbc14d 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -552,6 +552,7 @@ static inline void local_r4k_flush_cache_page(void *args)
pmd_t *pmdp;
pte_t *ptep;
void *vaddr;
+ int noflush = 0;
/*
* If ownes no valid ASID yet, cannot possibly have gotten
@@ -611,6 +612,7 @@ static inline void local_r4k_flush_cache_page(void *args)
if (cpu_context(cpu, mm) != 0)
drop_mmu_context(mm, cpu);
+ noflush = 1;
} else
vaddr ? r4k_blast_icache_page(addr) :
r4k_blast_icache_user_page(addr);
@@ -622,6 +624,13 @@ static inline void local_r4k_flush_cache_page(void *args)
else
kunmap_atomic(vaddr);
}
+
+ /* If we have I-cache aliasing, then blast it via coherent page. */
+ if (exec && cpu_has_ic_aliases && !noflush && !map_coherent) {
+ vaddr = kmap_coherent(page, addr);
+ r4k_blast_icache_page((unsigned long)vaddr);
+ kunmap_coherent();
+ }
}
static void r4k_flush_cache_page(struct vm_area_struct *vma,
@@ -1318,10 +1327,12 @@ static void probe_pcache(void)
c->icache.ways = 1;
}
- printk("Primary instruction cache %ldkB, %s, %s, linesize %d bytes.\n",
- icache_size >> 10,
+ printk("Primary instruction cache %ldkB, %s, %s, %slinesize %d bytes.\n",
+ icache_size >> 10, way_string[c->icache.ways],
c->icache.flags & MIPS_CACHE_VTAG ? "VIVT" : "VIPT",
- way_string[c->icache.ways], c->icache.linesz);
+ (c->icache.flags & MIPS_CACHE_ALIASES) ?
+ "I-cache aliases, " : "",
+ c->icache.linesz);
printk("Primary data cache %ldkB, %s, %s, %s, linesize %d bytes\n",
dcache_size >> 10, way_string[c->dcache.ways],
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 0dc604a..b1584d6 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -88,8 +88,6 @@ static void *__kmap_pgprot(struct page *page, unsigned long addr, pgprot_t prot)
pte_t pte;
int tlbidx;
- BUG_ON(Page_dcache_dirty(page));
-
pagefault_disable();
idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1);
idx += in_interrupt() ? FIX_N_COLOURS : 0;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-19 16:17 ` Steven J. Hill
(?)
@ 2015-02-20 19:17 ` Kevin Cernekee
2015-02-24 0:56 ` Leonid Yegoshin
-1 siblings, 1 reply; 24+ messages in thread
From: Kevin Cernekee @ 2015-02-20 19:17 UTC (permalink / raw)
To: Steven J. Hill; +Cc: IMG-MIPSLinuxKerneldevelopers, Linux MIPS Mailing List
On Thu, Feb 19, 2015 at 8:17 AM, Steven J. Hill <Steven.Hill@imgtec.com> wrote:
> From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
>
> Flush the D-cache before the page is given to a process
> as an executable (I-cache) page when the backing store
> is non-DMA I/O.
>
> Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
> Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
This patch seems to make several different changes to the cache
maintenance code all at once:
1) Add logic to handle virtually tagged D$ and perform extra flushes
on TLB updates
2) Add new write barriers betwen D$/I$ or D$/L2 flushes
3) Make __flush_anon_page() play nice with HIGHMEM on systems with cache aliases
and maybe a few more that I missed.
Would it be possible to split this out into individual commits, and
include more comprehensive changelogs for each one describing the
exact problem being solved?
Also, it would be helpful to clarify how this relates to the use of
swap (?) with a backing store that is non-DMA I/O. Do you have an
example of a situation where the existing code broke? A play-by-play
postmortem would make for interesting reading.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-20 19:17 ` Kevin Cernekee
@ 2015-02-24 0:56 ` Leonid Yegoshin
2015-02-24 1:13 ` Zenon Fortuna
2015-02-24 2:24 ` Maciej W. Rozycki
0 siblings, 2 replies; 24+ messages in thread
From: Leonid Yegoshin @ 2015-02-24 0:56 UTC (permalink / raw)
To: Kevin Cernekee, Steven J. Hill
Cc: IMG - MIPS Linux Kernel developers, Linux MIPS Mailing List
On 02/20/2015 11:17 AM, Kevin Cernekee wrote:
> On Thu, Feb 19, 2015 at 8:17 AM, Steven J. Hill <Steven.Hill@imgtec.com> wrote:
>> From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
>>
>> Flush the D-cache before the page is given to a process
>> as an executable (I-cache) page when the backing store
>> is non-DMA I/O.
>>
>> Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
>> Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
> This patch seems to make several different changes to the cache
> maintenance code all at once:
>
> 1) Add logic to handle virtually tagged D$
This is needed for 74K/1074K erratas. It is somehow was split from
006a851b10a395955c153a145ad8241494d43688 which was accepted upstream but
erratas not go through.
The HW behaviour is similar to virtually tagged D$ but it is a HW bug.
> and perform extra flushes
> on TLB updates
As I understand, it is about adding __update_cache() in
update_mmu_cache(), right?
If so, then - this code exists from the first git version of kernel from
Mr. Linus.
It was deleted by mistake, I think.
>
> 2) Add new write barriers betwen D$/I$ or D$/L2 flushes
It is required. MIPS32/64 R2 specs say:
> "For implementations which implement multiple level of caches without
> the inclusion property, the use of a SYNC
> instruction after the CACHE instruction is still needed whenever
> writeback data has to be resident in the next level of
> memory hierarchy."
So, if we need to transfer instruction from D$ to L2 then we should use
SYNC after CACHE D$ before operates with this data in L2. In other case
the CACHE for L2 may go ahead of completion of D$ for the same line and
flush a stale data.
The same is basically for transfer D$ --> I$ because in MIPS it is done
via L2 or memory.
>
> 3) Make __flush_anon_page() play nice with HIGHMEM on systems with cache aliases
>
> and maybe a few more that I missed.
4) It is basically a revert of patch 64f23ab30b1fe which kills a
performance in non Cavium Octeon CPUs, actually - any CPU which has no
D$ cache snooping in I$.
But just revert is incorrect, the another proper stuff is required for
correct operations.
>
> Would it be possible to split this out into individual commits, and
> include more comprehensive changelogs for each one describing the
> exact problem being solved?
I would ask Steven to do it. The original code dates back to 2.6.32 and
it was packed/split in different patches multiple times. After a lot of
split/join following patch acceptance/rejection we have what we have now.
In my opinion, the process of splitting into individual commits are
something wrong - some patches are accepted and some - not, and we have
a buggy code now. It should be packed into functional patches but each
patch should be a single workable commit. If multiple patches are needed
to fix a problem then result is sometime wrong.
>
> Also, it would be helpful to clarify how this relates to the use of
> swap (?) with a backing store that is non-DMA I/O. Do you have an
> example of a situation where the existing code broke? A play-by-play
> postmortem would make for interesting reading.
I guess, it is a little incorrect - this code is REQUIRED for non-DMA
I/O with root FS or swap but it is not enough. Another patch is still
needed to complete, see http://patchwork.linux-mips.org/patch/8635/
- Leonid.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 0:56 ` Leonid Yegoshin
@ 2015-02-24 1:13 ` Zenon Fortuna
2015-02-24 2:33 ` Maciej W. Rozycki
2015-02-24 2:24 ` Maciej W. Rozycki
1 sibling, 1 reply; 24+ messages in thread
From: Zenon Fortuna @ 2015-02-24 1:13 UTC (permalink / raw)
To: Leonid Yegoshin
Cc: Steven J. Hill, IMG - MIPS Linux Kernel developers,
Linux MIPS Mailing List
A small related chirp-in from the "lowly Linux userland":
Does the current system-call "cacheflush(2)" works with the newer kernels?
As the "man cacheflush" tells, it was supposed to work only on MIPS
based systems.
In the past I had some problems with it, so used related YAMON functions
(which worked
better).
Maybe it could be made working for MIPS again?
(is it supposed to work with current kernels?)
Cache flushing is a useful feature for some benchmarks (and customers
had requested
related tests in the past).
-zenon
Leonid Yegoshin wrote:
> On 02/20/2015 11:17 AM, Kevin Cernekee wrote:
>> On Thu, Feb 19, 2015 at 8:17 AM, Steven J. Hill
>> <Steven.Hill@imgtec.com> wrote:
>>> From: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
>>>
>>> Flush the D-cache before the page is given to a process
>>> as an executable (I-cache) page when the backing store
>>> is non-DMA I/O.
>>>
>>> Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
>>> Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
>> This patch seems to make several different changes to the cache
>> maintenance code all at once:
>>
>> 1) Add logic to handle virtually tagged D$
> This is needed for 74K/1074K erratas. It is somehow was split from
> 006a851b10a395955c153a145ad8241494d43688 which was accepted upstream
> but erratas not go through.
>
> The HW behaviour is similar to virtually tagged D$ but it is a HW bug.
>
>> and perform extra flushes
>> on TLB updates
> As I understand, it is about adding __update_cache() in
> update_mmu_cache(), right?
> If so, then - this code exists from the first git version of kernel
> from Mr. Linus.
> It was deleted by mistake, I think.
>
>>
>> 2) Add new write barriers betwen D$/I$ or D$/L2 flushes
> It is required. MIPS32/64 R2 specs say:
>
>> "For implementations which implement multiple level of caches without
>> the inclusion property, the use of a SYNC
>> instruction after the CACHE instruction is still needed whenever
>> writeback data has to be resident in the next level of
>> memory hierarchy."
>
> So, if we need to transfer instruction from D$ to L2 then we should
> use SYNC after CACHE D$ before operates with this data in L2. In other
> case the CACHE for L2 may go ahead of completion of D$ for the same
> line and flush a stale data.
>
> The same is basically for transfer D$ --> I$ because in MIPS it is
> done via L2 or memory.
>
>
>>
>> 3) Make __flush_anon_page() play nice with HIGHMEM on systems with
>> cache aliases
>>
>> and maybe a few more that I missed.
> 4) It is basically a revert of patch 64f23ab30b1fe which kills a
> performance in non Cavium Octeon CPUs, actually - any CPU which has no
> D$ cache snooping in I$.
>
> But just revert is incorrect, the another proper stuff is required for
> correct operations.
>>
>> Would it be possible to split this out into individual commits, and
>> include more comprehensive changelogs for each one describing the
>> exact problem being solved?
> I would ask Steven to do it. The original code dates back to 2.6.32
> and it was packed/split in different patches multiple times. After a
> lot of split/join following patch acceptance/rejection we have what we
> have now.
>
> In my opinion, the process of splitting into individual commits are
> something wrong - some patches are accepted and some - not, and we
> have a buggy code now. It should be packed into functional patches but
> each patch should be a single workable commit. If multiple patches are
> needed to fix a problem then result is sometime wrong.
>
>>
>> Also, it would be helpful to clarify how this relates to the use of
>> swap (?) with a backing store that is non-DMA I/O. Do you have an
>> example of a situation where the existing code broke? A play-by-play
>> postmortem would make for interesting reading.
>
> I guess, it is a little incorrect - this code is REQUIRED for non-DMA
> I/O with root FS or swap but it is not enough. Another patch is still
> needed to complete, see http://patchwork.linux-mips.org/patch/8635/
>
> - Leonid.
>
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 0:56 ` Leonid Yegoshin
2015-02-24 1:13 ` Zenon Fortuna
@ 2015-02-24 2:24 ` Maciej W. Rozycki
2015-02-24 16:20 ` Steven J. Hill
1 sibling, 1 reply; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-02-24 2:24 UTC (permalink / raw)
To: Leonid Yegoshin
Cc: Kevin Cernekee, Steven J. Hill,
IMG - MIPS Linux Kernel developers, Linux MIPS Mailing List
On Mon, 23 Feb 2015, Leonid Yegoshin wrote:
> The same is basically for transfer D$ --> I$ because in MIPS it is done via L2
> or memory.
The original issue aside (I don't want to dive into it) this I believe is
left to an implementer's discretion and there are MIPS implementations
indeed that fill I$ directly from D$; IIRC Alchemy silicon and its
descendants.
Maciej
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 1:13 ` Zenon Fortuna
@ 2015-02-24 2:33 ` Maciej W. Rozycki
2015-02-24 21:06 ` Leonid Yegoshin
0 siblings, 1 reply; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-02-24 2:33 UTC (permalink / raw)
To: Zenon Fortuna
Cc: Leonid Yegoshin, Steven J. Hill,
IMG - MIPS Linux Kernel developers, Linux MIPS Mailing List
On Mon, 23 Feb 2015, Zenon Fortuna wrote:
> Does the current system-call "cacheflush(2)" works with the newer kernels?
> As the "man cacheflush" tells, it was supposed to work only on MIPS based
> systems.
It absolutely has to work, on the MIPS target GCC emits code invoking it
to synchronise trampolines built at the run time on the stack (used for
calling nested functions, a C language extension borrowed from Pascal,
etc.), before passing execution there. Verification of this syscall is
probably implicitly covered by the GCC test suite already.
Maciej
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 2:24 ` Maciej W. Rozycki
@ 2015-02-24 16:20 ` Steven J. Hill
0 siblings, 0 replies; 24+ messages in thread
From: Steven J. Hill @ 2015-02-24 16:20 UTC (permalink / raw)
To: Maciej W. Rozycki, Leonid Yegoshin
Cc: Kevin Cernekee, Linux MIPS Mailing List
On 02/23/2015 08:24 PM, Maciej W. Rozycki wrote:
> On Mon, 23 Feb 2015, Leonid Yegoshin wrote:
>
>> The same is basically for transfer D$ --> I$ because in MIPS it is done via L2
>> or memory.
>
> The original issue aside (I don't want to dive into it) this I believe is
> left to an implementer's discretion and there are MIPS implementations
> indeed that fill I$ directly from D$; IIRC Alchemy silicon and its
> descendants.
>
> Maciej
>
I am tracking down even more HIGHMEM bugs, so I will rework these
patches, clean-up commit messages and post again. Thanks for all the
feedback.
Steve
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 2:33 ` Maciej W. Rozycki
@ 2015-02-24 21:06 ` Leonid Yegoshin
2015-02-24 21:51 ` Maciej W. Rozycki
0 siblings, 1 reply; 24+ messages in thread
From: Leonid Yegoshin @ 2015-02-24 21:06 UTC (permalink / raw)
To: Maciej W. Rozycki, Zenon Fortuna
Cc: Steven J. Hill, IMG - MIPS Linux Kernel developers,
Linux MIPS Mailing List
On 02/23/2015 06:33 PM, Maciej W. Rozycki wrote:
> On Mon, 23 Feb 2015, Zenon Fortuna wrote:
>
>> Does the current system-call "cacheflush(2)" works with the newer kernels?
>> As the "man cacheflush" tells, it was supposed to work only on MIPS based
>> systems.
> It absolutely has to work, on the MIPS target GCC emits code invoking it
> to synchronise trampolines built at the run time on the stack (used for
> calling nested functions, a C language extension borrowed from Pascal,
> etc.), before passing execution there. Verification of this syscall is
> probably implicitly covered by the GCC test suite already.
>
> Maciej
cacheflush() syscall traps into kernel and it executes I and D caches
flushing.
However, it's implementation in 'master' branch from Linus tree is
wrong: if you call it in multicore environment for size > L1 cache size
then it does it incorrectly: doesn't call IPI for index cacheops.
The correct way is ... sorry, can't find it in LMO...
- Leonid.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 21:06 ` Leonid Yegoshin
@ 2015-02-24 21:51 ` Maciej W. Rozycki
2015-02-24 21:57 ` Leonid Yegoshin
0 siblings, 1 reply; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-02-24 21:51 UTC (permalink / raw)
To: Leonid Yegoshin
Cc: Zenon Fortuna, Steven J. Hill, IMG - MIPS Linux Kernel developers,
Linux MIPS Mailing List
On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
> > It absolutely has to work, on the MIPS target GCC emits code invoking it
> > to synchronise trampolines built at the run time on the stack (used for
> > calling nested functions, a C language extension borrowed from Pascal,
> > etc.), before passing execution there. Verification of this syscall is
> > probably implicitly covered by the GCC test suite already.
> >
> > Maciej
> cacheflush() syscall traps into kernel and it executes I and D caches
> flushing.
>
> However, it's implementation in 'master' branch from Linus tree is wrong: if
> you call it in multicore environment for size > L1 cache size then it does it
> incorrectly: doesn't call IPI for index cacheops.
>
> The correct way is ... sorry, can't find it in LMO...
Hmm, on SMP using hit operations for cacheflush(2) that rely on the
hardware cache coherency protocol should be cheaper up to at least the
size of the cache times the number of processors. To say nothing of the
the overhead of sending and receiving IPIs.
For simplicity perhaps on SMP we should just always use hit operations
regardless of the size requested. It's not like using cacheflush(2) for
large blocks is that common. And GCC trampolines consist of a couple of
instructions only, they'll never hit the problem.
Maciej
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 21:51 ` Maciej W. Rozycki
@ 2015-02-24 21:57 ` Leonid Yegoshin
2015-02-24 22:50 ` Maciej W. Rozycki
0 siblings, 1 reply; 24+ messages in thread
From: Leonid Yegoshin @ 2015-02-24 21:57 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Zenon Fortuna, Steven J. Hill, IMG - MIPS Linux Kernel developers,
Linux MIPS Mailing List
On 02/24/2015 01:51 PM, Maciej W. Rozycki wrote:
> On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
>
>>> It absolutely has to work, on the MIPS target GCC emits code invoking it
>>> to synchronise trampolines built at the run time on the stack (used for
>>> calling nested functions, a C language extension borrowed from Pascal,
>>> etc.), before passing execution there. Verification of this syscall is
>>> probably implicitly covered by the GCC test suite already.
>>>
>>> Maciej
>> cacheflush() syscall traps into kernel and it executes I and D caches
>> flushing.
>>
>> However, it's implementation in 'master' branch from Linus tree is wrong: if
>> you call it in multicore environment for size > L1 cache size then it does it
>> incorrectly: doesn't call IPI for index cacheops.
>>
>> The correct way is ... sorry, can't find it in LMO...
> Hmm, on SMP using hit operations for cacheflush(2) that rely on the
> hardware cache coherency protocol should be cheaper up to at least the
> size of the cache times the number of processors. To say nothing of the
> the overhead of sending and receiving IPIs.
>
> For simplicity perhaps on SMP we should just always use hit operations
> regardless of the size requested.
High performance folks may not like doing a lot of stuff for 8MB VMA
release instead of flushing 64KB.
Especially taking into account TLB exceptions and postprocessing in
fixup_exception() for swapped-out/not-yet-loaded-ELF blocks.
- Leonid.
> It's not like using cacheflush(2) for
> large blocks is that common. And GCC trampolines consist of a couple of
> instructions only, they'll never hit the problem.
>
> Maciej
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 21:57 ` Leonid Yegoshin
@ 2015-02-24 22:50 ` Maciej W. Rozycki
2015-02-24 22:57 ` David Daney
2015-02-24 23:15 ` Leonid Yegoshin
0 siblings, 2 replies; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-02-24 22:50 UTC (permalink / raw)
To: Leonid Yegoshin
Cc: Zenon Fortuna, Steven J. Hill, IMG - MIPS Linux Kernel developers,
Linux MIPS Mailing List
On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
> > For simplicity perhaps on SMP we should just always use hit operations
> > regardless of the size requested.
>
> High performance folks may not like doing a lot of stuff for 8MB VMA release
> instead of flushing 64KB.
What kind of a use case is that, what does it do?
> Especially taking into account TLB exceptions and postprocessing in
> fixup_exception() for swapped-out/not-yet-loaded-ELF blocks.
The normal use for cacheflush(2) I know of is for self-modifying or other
run-time-generated code, to synchronise caches after a block of machine
code has been patched in -- SYNCI can also be used for that purpose these
days, but the syscall long predates the presence of this instruction in
the architecture .
I fail to see any other need to force data out of cache in a user program
(apart from also the corner case of benchmarking cold caches, such as in
Zenon's case, but there the performance of the preparatory cache
invalidation does not really matter). Why would you expect VM to have
been swapped out or not loaded where data has just been written? Why
would you want to call cacheflush(2) for blocks of data that haven't been
written?
Maciej
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 22:50 ` Maciej W. Rozycki
@ 2015-02-24 22:57 ` David Daney
2015-02-24 23:19 ` Leonid Yegoshin
2015-02-24 23:15 ` Leonid Yegoshin
1 sibling, 1 reply; 24+ messages in thread
From: David Daney @ 2015-02-24 22:57 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Leonid Yegoshin, Zenon Fortuna, Steven J. Hill,
IMG - MIPS Linux Kernel developers, Linux MIPS Mailing List
On 02/24/2015 02:50 PM, Maciej W. Rozycki wrote:
> On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
>
>>> For simplicity perhaps on SMP we should just always use hit operations
>>> regardless of the size requested.
>>
>> High performance folks may not like doing a lot of stuff for 8MB VMA release
>> instead of flushing 64KB.
>
> What kind of a use case is that, what does it do?
>
>> Especially taking into account TLB exceptions and postprocessing in
>> fixup_exception() for swapped-out/not-yet-loaded-ELF blocks.
>
> The normal use for cacheflush(2) I know of is for self-modifying or other
> run-time-generated code, to synchronise caches after a block of machine
> code has been patched in -- SYNCI can also be used for that purpose these
> days,
SYNCI is only useful in non-SMP kernels.
If a thread is migrated to a different CPU between the SYNCI, and the
attempt to execute the freshly generated code, the new CPU can still
have a dirty ICACHE. So for Linux userspace, cacheflush(2) is your only
option.
David Daney
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 22:50 ` Maciej W. Rozycki
2015-02-24 22:57 ` David Daney
@ 2015-02-24 23:15 ` Leonid Yegoshin
1 sibling, 0 replies; 24+ messages in thread
From: Leonid Yegoshin @ 2015-02-24 23:15 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Zenon Fortuna, Steven J. Hill, IMG - MIPS Linux Kernel developers,
Linux MIPS Mailing List
On 02/24/2015 02:50 PM, Maciej W. Rozycki wrote:
> On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
>
>>> For simplicity perhaps on SMP we should just always use hit operations
>>> regardless of the size requested.
>> High performance folks may not like doing a lot of stuff for 8MB VMA release
>> instead of flushing 64KB.
> What kind of a use case is that, what does it do?
>
>
cacheflush() calls flush_icache_range(). And we see:
linux-yegoshin:/space/yegoshin/MIPS-kernel/linux-mips.org/linux-mti% gid
flush_icache_range | grep -v arch/
include/asm-generic/cacheflush.h:20:#define flush_icache_range(start,
end) do { } while (0)
fs/binfmt_flat.c:787: flush_icache_range(start_code, end_code);
fs/exec.c:823: flush_icache_range(addr, addr + len);
kernel/module.c:2886: flush_icache_range((unsigned
long)mod->module_init,
kernel/module.c:2889: flush_icache_range((unsigned long)mod->module_core,
mm/nommu.c:532: flush_icache_range(mm->brk, brk);
mm/nommu.c:1441: flush_icache_range(region->vm_start,
region->vm_end);
drivers/misc/lkdtm.c:346: flush_icache_range((unsigned long)dst,
(unsigned long)dst + EXEC_SIZE);
drivers/misc/lkdtm.c:361: flush_icache_range((unsigned long)dst,
(unsigned long)dst + EXEC_SIZE);
drivers/misc/lkdtm.c:519: flush_icache_range((unsigned long)ptr,
kernel/debug/debug_core.c:243: flush_icache_range(addr, addr +
BREAK_INSTR_SIZE);
kernel/debug/gdbstub.c:383: flush_icache_range(addr, addr +
length);
drivers/video/console/sticore.c:254: flush_icache_range(start, end);
Documentation/cachetlb.txt:369: void flush_icache_range(unsigned long
start, unsigned long end)
It is not for VMA release, I was wrong here, but there are still some
interesting use cases for flush_icache_range().
Note: it is not cacheflush() bug, it is bug in r4k_on_each_cpu(). I have
a patch named
Author: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Date: Mon Apr 1 20:10:30 2013 -0700
MIPS: Cache flush functions are reworked.
This patch is a preparation for EVA support in kernel.
However, it also fixes a bug then index cacheop was not ran
on multiple CPUs with unsafe index cacheops (flush_cache_vmap,
flush_icache_range, flush_cache_range, __flush_cache_all).
Additionally, it optimizes a usage of index and address cacheops for
address range flushes depending from address range size.
Because of that reasons it is a separate patch from EVA support.
Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Steven J. Hill <Steven.Hill@imgtec.com>
(cherry picked from commit 6b05dd71da1136fbad0ce642790c4c99343f05e7)
but it is still doesn't go through LMO.
- Leonid.
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 22:57 ` David Daney
@ 2015-02-24 23:19 ` Leonid Yegoshin
2015-02-24 23:58 ` David Daney
2015-02-25 0:07 ` Maciej W. Rozycki
0 siblings, 2 replies; 24+ messages in thread
From: Leonid Yegoshin @ 2015-02-24 23:19 UTC (permalink / raw)
To: David Daney, Maciej W. Rozycki
Cc: Zenon Fortuna, Steven J. Hill, IMG - MIPS Linux Kernel developers,
Linux MIPS Mailing List
On 02/24/2015 02:57 PM, David Daney wrote:
> On 02/24/2015 02:50 PM, Maciej W. Rozycki wrote:
>> On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
>>
>>>> For simplicity perhaps on SMP we should just always use hit
>>>> operations
>>>> regardless of the size requested.
>>>
>>> High performance folks may not like doing a lot of stuff for 8MB VMA
>>> release
>>> instead of flushing 64KB.
>>
>> What kind of a use case is that, what does it do?
>>
>>> Especially taking into account TLB exceptions and postprocessing in
>>> fixup_exception() for swapped-out/not-yet-loaded-ELF blocks.
>>
>> The normal use for cacheflush(2) I know of is for self-modifying or
>> other
>> run-time-generated code, to synchronise caches after a block of machine
>> code has been patched in -- SYNCI can also be used for that purpose
>> these
>> days,
>
> SYNCI is only useful in non-SMP kernels.
Yes, until MIPS R6. I pressed hard on Arch team to change vague words in
SYNCI description and now (MIPS R6) it has words requiring execution on
all cores:
> "SYNCI globalization:
> Release 6: SYNCI globalization (as described below) is required:
> compliant implementations must globalize SYNCI.
> Portable software can rely on this behavior, and use SYNCI rather than
> expensive “instruction cache shootdown”
> using inter-processor interrupts."
- Leonid.
>
> If a thread is migrated to a different CPU between the SYNCI, and the
> attempt to execute the freshly generated code, the new CPU can still
> have a dirty ICACHE. So for Linux userspace, cacheflush(2) is your
> only option.
>
> David Daney
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 23:19 ` Leonid Yegoshin
@ 2015-02-24 23:58 ` David Daney
2015-02-25 0:07 ` Maciej W. Rozycki
1 sibling, 0 replies; 24+ messages in thread
From: David Daney @ 2015-02-24 23:58 UTC (permalink / raw)
To: Leonid Yegoshin
Cc: Maciej W. Rozycki, Zenon Fortuna, Steven J. Hill,
IMG - MIPS Linux Kernel developers, Linux MIPS Mailing List
On 02/24/2015 03:19 PM, Leonid Yegoshin wrote:
> On 02/24/2015 02:57 PM, David Daney wrote:
>> On 02/24/2015 02:50 PM, Maciej W. Rozycki wrote:
>>> On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
>>>
>>>>> For simplicity perhaps on SMP we should just always use hit
>>>>> operations
>>>>> regardless of the size requested.
>>>>
>>>> High performance folks may not like doing a lot of stuff for 8MB VMA
>>>> release
>>>> instead of flushing 64KB.
>>>
>>> What kind of a use case is that, what does it do?
>>>
>>>> Especially taking into account TLB exceptions and postprocessing in
>>>> fixup_exception() for swapped-out/not-yet-loaded-ELF blocks.
>>>
>>> The normal use for cacheflush(2) I know of is for self-modifying or
>>> other
>>> run-time-generated code, to synchronise caches after a block of machine
>>> code has been patched in -- SYNCI can also be used for that purpose
>>> these
>>> days,
>>
>> SYNCI is only useful in non-SMP kernels.
> Yes, until MIPS R6. I pressed hard on Arch team to change vague words in
> SYNCI description and now (MIPS R6) it has words requiring execution on
> all cores:
>
>> "SYNCI globalization:
>> Release 6: SYNCI globalization (as described below) is required:
>> compliant implementations must globalize SYNCI.
>> Portable software can rely on this behavior, and use SYNCI rather than
>> expensive “instruction cache shootdown”
>> using inter-processor interrupts."
Wow. I guess implementing -msynci wasn't a complete waste of time after
all.
In any event, it is irrelevant with respect to the semantics of
cacheflush(2), which still must be properly implemented.
David Daney
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-24 23:19 ` Leonid Yegoshin
2015-02-24 23:58 ` David Daney
@ 2015-02-25 0:07 ` Maciej W. Rozycki
2015-02-25 0:38 ` David Daney
1 sibling, 1 reply; 24+ messages in thread
From: Maciej W. Rozycki @ 2015-02-25 0:07 UTC (permalink / raw)
To: Leonid Yegoshin
Cc: David Daney, Zenon Fortuna, Steven J. Hill,
IMG - MIPS Linux Kernel developers, Linux MIPS Mailing List
On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
> > SYNCI is only useful in non-SMP kernels.
> Yes, until MIPS R6. I pressed hard on Arch team to change vague words in SYNCI
> description and now (MIPS R6) it has words requiring execution on all cores:
>
> > "SYNCI globalization:
> > Release 6: SYNCI globalization (as described below) is required: compliant
> > implementations must globalize SYNCI.
> > Portable software can rely on this behavior, and use SYNCI rather than
> > expensive “instruction cache shootdown”
> > using inter-processor interrupts."
Good, thanks for enforcing sanity!
> > If a thread is migrated to a different CPU between the SYNCI, and the
> > attempt to execute the freshly generated code, the new CPU can still have a
> > dirty ICACHE. So for Linux userspace, cacheflush(2) is your only option.
Is it not a kernel bug then? Shouldn't migration code enforce cache
coherency manually if hardware does not? User software is supposed to
have a consistent view of the system and such details as being run on a
multiprocessor should be completely hidden.
Maciej
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O.
2015-02-25 0:07 ` Maciej W. Rozycki
@ 2015-02-25 0:38 ` David Daney
0 siblings, 0 replies; 24+ messages in thread
From: David Daney @ 2015-02-25 0:38 UTC (permalink / raw)
To: Maciej W. Rozycki
Cc: Leonid Yegoshin, Zenon Fortuna, Steven J. Hill,
IMG - MIPS Linux Kernel developers, Linux MIPS Mailing List
On 02/24/2015 04:07 PM, Maciej W. Rozycki wrote:
> On Tue, 24 Feb 2015, Leonid Yegoshin wrote:
>
>>> SYNCI is only useful in non-SMP kernels.
>> Yes, until MIPS R6. I pressed hard on Arch team to change vague words in SYNCI
>> description and now (MIPS R6) it has words requiring execution on all cores:
>>
>>> "SYNCI globalization:
>>> Release 6: SYNCI globalization (as described below) is required: compliant
>>> implementations must globalize SYNCI.
>>> Portable software can rely on this behavior, and use SYNCI rather than
>>> expensive “instruction cache shootdown”
>>> using inter-processor interrupts."
>
> Good, thanks for enforcing sanity!
>
>>> If a thread is migrated to a different CPU between the SYNCI, and the
>>> attempt to execute the freshly generated code, the new CPU can still have a
>>> dirty ICACHE. So for Linux userspace, cacheflush(2) is your only option.
>
> Is it not a kernel bug then?
I don't think so. cacheflush(2) is the only way for the kernel to know
that it needs to do extra work. The alternative is to not use ASIDs in
the TLB and caches, and just invalidate all caches whenever we change
contexts.
We carry a lot complexity in the kernel to avoid unnecessary TLB and
cache invalidations. All that goes out the window (with the performance
improvements that it brings) if you want to magically make cacheflush(2)
unnecessary.
> Shouldn't migration code enforce cache
> coherency manually if hardware does not? User software is supposed to
> have a consistent view of the system and such details as being run on a
> multiprocessor should be completely hidden.
Traditionally on MIPS, the ICache is not coherent, going from non-SMP to
SMP doesn't magically make it coherent. Part of the ABI is that if you
have self modifying code, you must call cacheflush(2) If you violate
the ABI, it won't work.
David Daney
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2015-02-25 0:38 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-02-19 16:17 [PATCH V2 0/3] HIGHMEM and cache flush fixes Steven J. Hill
2015-02-19 16:17 ` Steven J. Hill
2015-02-19 16:17 ` [PATCH V2 1/3] MIPS: Fix cache flushing for swap pages with non-DMA I/O Steven J. Hill
2015-02-19 16:17 ` Steven J. Hill
2015-02-20 19:17 ` Kevin Cernekee
2015-02-24 0:56 ` Leonid Yegoshin
2015-02-24 1:13 ` Zenon Fortuna
2015-02-24 2:33 ` Maciej W. Rozycki
2015-02-24 21:06 ` Leonid Yegoshin
2015-02-24 21:51 ` Maciej W. Rozycki
2015-02-24 21:57 ` Leonid Yegoshin
2015-02-24 22:50 ` Maciej W. Rozycki
2015-02-24 22:57 ` David Daney
2015-02-24 23:19 ` Leonid Yegoshin
2015-02-24 23:58 ` David Daney
2015-02-25 0:07 ` Maciej W. Rozycki
2015-02-25 0:38 ` David Daney
2015-02-24 23:15 ` Leonid Yegoshin
2015-02-24 2:24 ` Maciej W. Rozycki
2015-02-24 16:20 ` Steven J. Hill
2015-02-19 16:17 ` [PATCH V2 2/3] MIPS: Highmem: Fixes for cache aliasing and color Steven J. Hill
2015-02-19 16:17 ` Steven J. Hill
2015-02-19 16:17 ` [PATCH V2 3/3] MIPS: Fix I-cache flushing for kmap'd pages Steven J. Hill
2015-02-19 16:17 ` Steven J. Hill
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.