From patchwork Tue Feb 15 01:58:53 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John David Anglin X-Patchwork-Id: 557531 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p1F1x0kL026212 for ; Tue, 15 Feb 2011 01:59:00 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752521Ab1BOB65 (ORCPT ); Mon, 14 Feb 2011 20:58:57 -0500 Received: from hiauly1.hia.nrc.ca ([132.246.10.84]:4581 "EHLO hiauly1.hia.nrc.ca" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751196Ab1BOB64 (ORCPT ); Mon, 14 Feb 2011 20:58:56 -0500 Received: by hiauly1.hia.nrc.ca (Postfix, from userid 1000) id 17BA04DF4; Mon, 14 Feb 2011 20:58:53 -0500 (EST) Date: Mon, 14 Feb 2011 20:58:53 -0500 From: John David Anglin To: James.Bottomley@HansenPartnership.com, dave.anglin@nrc-cnrc.gc.ca, linux-parisc@vger.kernel.org Subject: Re: [PATCH] parisc: Improve dcache flush on PA8800/PA8900 Message-ID: <20110215015852.GA6615@hiauly1.hia.nrc.ca> Reply-To: John David Anglin References: <20110210170033.4317E4ED8@hiauly1.hia.nrc.ca> <20110210200044.203164E01@hiauly1.hia.nrc.ca> <20110212161846.GA24076@hiauly1.hia.nrc.ca> <20110213193934.GA28834@hiauly1.hia.nrc.ca> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20110213193934.GA28834@hiauly1.hia.nrc.ca> Organization: nrc.ca User-Agent: Mutt/1.5.16 (2007-06-09) Sender: linux-parisc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-parisc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 15 Feb 2011 01:59:00 +0000 (UTC) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 3f11331..f90a330 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -276,10 +278,10 @@ __flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, void flush_dcache_page(struct page *page) { struct address_space *mapping = page_mapping(page); - struct vm_area_struct *mpnt; + struct vm_area_struct *mpnt, *mpnt_wrt, *mpnt_nwrt; struct prio_tree_iter iter; unsigned long offset; - unsigned long addr, old_addr = 0; + unsigned long addr, addr_wrt, addr_nwrt; pgoff_t pgoff; if (mapping && !mapping_mapped(mapping)) { @@ -292,26 +294,69 @@ void flush_dcache_page(struct page *page) if (!mapping) return; + addr_wrt = 0; + mpnt_wrt = NULL; + addr_nwrt = 0; + mpnt_nwrt = NULL; pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); /* We have carefully arranged in arch_get_unmapped_area() that - * *any* mappings of a file are always congruently mapped (whether - * declared as MAP_PRIVATE or MAP_SHARED), so we only need - * to flush one address here for them all to become coherent */ + * all shared mappings of a file are congruently mapped, so we + * only need to flush one address here for them all to become + * coherent. However, non-shared fixed mappings of executables + * are not congruently mapped on the boundary page between text + * and data. Further, the data segment sometimes occurs before + * the text segment. While it is unlikely that a dirty cache + * line would result from accesses through the text mapping, + * it is possible that this could occur since binutils doesn't + * ensure that the data segment starts on a page boundary. */ flush_dcache_mmap_lock(mapping); + + /* Scan for inequivalent aliases. */ vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; addr = mpnt->vm_start + offset; - if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { - __flush_cache_page(mpnt, addr, page_to_phys(page)); - if (old_addr) - printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); - old_addr = addr; + if (mpnt->vm_flags & VM_WRITE) { + if (addr_wrt == 0) { + addr_wrt = addr; + mpnt_wrt = mpnt; + } + else if ((addr_wrt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) + goto flush_inequivalent; } + else { + if (addr_nwrt == 0) { + addr_nwrt = addr; + mpnt_nwrt = mpnt; + } + else if ((addr_nwrt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) + goto flush_inequivalent; + } + } + flush_dcache_mmap_unlock(mapping); + + /* Common case where all writeable aliases are equivalent and + * all non writeable aliases are equivalent. */ + if (addr_wrt) + __flush_cache_page(mpnt_wrt, addr_wrt, page_to_phys(page)); + if (addr_nwrt && + (!addr_wrt || (addr_nwrt & (SHMLBA - 1)) != (addr_wrt & (SHMLBA - 1)))) + __flush_cache_page(mpnt_nwrt, addr_nwrt, page_to_phys(page)); + return; + +flush_inequivalent: + vma_prio_tree_foreach(mpnt, &iter, &mapping->i_mmap, pgoff, pgoff) { + offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; + addr = mpnt->vm_start + offset; + + printk(KERN_ERR "INEQUIVALENT ALIASES: page 0x%lx addr 0x%lx in file %s with flags 0x%lx\n", (unsigned long) page, addr, mpnt->vm_file ? (char *) mpnt->vm_file->f_path.dentry->d_name.name : "(null)", mpnt->vm_flags); + + __flush_cache_page(mpnt, addr, page_to_phys(page)); } flush_dcache_mmap_unlock(mapping); + return; } EXPORT_SYMBOL(flush_dcache_page);