[parisc-linux] Re: [parisc-linux-cvs] linux-2.6 jejb
James Bottomley
James.Bottomley at steeleye.com
Tue Apr 6 15:37:15 MDT 2004
On Tue, 2004-04-06 at 16:34, James Bottomley wrote:
> CVSROOT: /var/cvs
> Module name: linux-2.6
> Changes by: jejb 04/04/06 15:34:46
>
> Modified files:
> . : Makefile
> arch/parisc/kernel: cache.c
>
> Log message:
> Fix flush_dcache_page
Index: arch/parisc/kernel/cache.c
===================================================================
RCS file: /var/cvs/linux-2.6/arch/parisc/kernel/cache.c,v
retrieving revision 1.6
diff -u -r1.6 cache.c
--- a/arch/parisc/kernel/cache.c 5 Apr 2004 02:47:39 -0000 1.6
+++ b/arch/parisc/kernel/cache.c 6 Apr 2004 21:30:44 -0000
@@ -227,6 +227,32 @@
disable_sr_hashing_asm(srhash_type);
}
+/* Simple function to work out if we have an existing address translation
+ * for a user space vma. */
+static inline int translation_exists(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ pgd_t *pgd = pgd_offset(vma->vm_mm, addr);
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if(pgd_none(*pgd))
+ return 0;
+
+ pmd = pmd_offset(pgd, addr);
+ if(pmd_none(*pmd) || pmd_bad(*pmd))
+ return 0;
+
+ pte = pte_offset_map(pmd, addr);
+
+ /* The PA flush mappings show up as pte_none, but they're
+ * valid none the less */
+ if(pte_none(*pte) && ((pte_val(*pte) & _PAGE_FLUSH) == 0))
+ return 0;
+ return 1;
+}
+
+
void __flush_dcache_page(struct page *page)
{
struct mm_struct *mm = current->active_mm;
@@ -237,19 +263,15 @@
if (!page->mapping)
return;
- /* check shared list first if it's not empty...it's usually
- * the shortest */
+
+ /* We have ensured in arch_get_unmapped_area() that all shared
+ * mappings are mapped at equivalent addresses, so we only need
+ * to flush one for them all to become coherent */
list_for_each(l, &page->mapping->i_mmap_shared) {
struct vm_area_struct *mpnt;
- unsigned long off;
+ unsigned long off, addr;
- anyvma = mpnt = list_entry(l, struct vm_area_struct, shared);
-
- /*
- * If this VMA is not in our MM, we can ignore it.
- */
- if (mpnt->vm_mm != mm)
- continue;
+ mpnt = list_entry(l, struct vm_area_struct, shared);
if (page->index < mpnt->vm_pgoff)
continue;
@@ -258,25 +280,51 @@
if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
continue;
- flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
+ addr = mpnt->vm_start + (off << PAGE_SHIFT);
+
+ /* flush instructions produce non access tlb misses.
+ * On PA, we nullify these instructions rather than
+ * taking a page fault if the pte doesn't exist, so we
+ * have to find a congruent address with an existing
+ * translation */
+
+ if (!translation_exists(mpnt, addr))
+ continue;
+
+ anyvma = mpnt;
+
+ /*
+ * We try first to find a page in our current user process
+ */
+ if (mpnt->vm_mm != mm)
+ continue;
+
+
+ flush_cache_page(mpnt, addr);
/* All user shared mappings should be equivalently mapped,
* so once we've flushed one we should be ok
*/
- return;
+ goto flush_unshared;
}
- /* then check private mapping list for read only shared mappings
- * which are flagged by VM_MAYSHARE */
- list_for_each(l, &page->mapping->i_mmap) {
- struct vm_area_struct *mpnt;
- unsigned long off;
+ /* OK, shared page but not in our current process' address space */
+ if (anyvma) {
+ unsigned long addr = anyvma->vm_start
+ + ((page->index - anyvma->vm_pgoff) << PAGE_SHIFT);
+ flush_cache_page(anyvma, addr);
+ }
- anyvma = mpnt = list_entry(l, struct vm_area_struct, shared);
+ flush_unshared:
+ /* Private mappings will not have congruent addresses, so we
+ * have to flush each of them individually to make the change
+ * in the kernel page visible */
+ list_for_each(l, &page->mapping->i_mmap) {
+ struct vm_area_struct *mpnt;
+ unsigned long off, addr;
- if (mpnt->vm_mm != mm || !(mpnt->vm_flags & VM_MAYSHARE))
- continue;
+ mpnt = list_entry(l, struct vm_area_struct, shared);
if (page->index < mpnt->vm_pgoff)
continue;
@@ -285,20 +333,15 @@
if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
continue;
- flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
+ addr = mpnt->vm_start + (off << PAGE_SHIFT);
- /* All user shared mappings should be equivalently mapped,
- * so once we've flushed one we should be ok
- */
- return;
- }
- /* This is the problem case. We failed to find the page to be
- * flushed in the current vma thus we have to flush it in some
- * other user process */
- if (likely(anyvma)) {
- unsigned long addr = anyvma->vm_start
- + ((page->index - anyvma->vm_pgoff) << PAGE_SHIFT);
- flush_user_cache_page_non_current(anyvma, addr);
+ /* This is just for speed. If the page translation isn't
+ * there there's no point exciting the nadtlb handler into
+ * a nullification frenzy */
+ if(!translation_exists(mpnt, addr))
+ continue;
+
+ flush_cache_page(mpnt, addr);
}
}
EXPORT_SYMBOL(__flush_dcache_page);
More information about the parisc-linux
mailing list