From patchwork Thu Oct 29 08:00:13 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Williams X-Patchwork-Id: 7517051 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id A40B9BEEA4 for ; Thu, 29 Oct 2015 08:02:28 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A14F820943 for ; Thu, 29 Oct 2015 08:02:27 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8370520942 for ; Thu, 29 Oct 2015 08:02:26 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zri8d-0000Go-WD; Thu, 29 Oct 2015 08:00:48 +0000 Received: from mga09.intel.com ([134.134.136.24]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zri8a-0000EU-PO for linux-arm-kernel@lists.infradead.org; Thu, 29 Oct 2015 08:00:45 +0000 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP; 29 Oct 2015 01:00:23 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,213,1444719600"; d="scan'208";a="837776412" Received: from orsmsx106.amr.corp.intel.com ([10.22.225.133]) by orsmga002.jf.intel.com with ESMTP; 29 Oct 2015 01:00:15 -0700 Received: from orsmsx151.amr.corp.intel.com (10.22.226.38) by ORSMSX106.amr.corp.intel.com (10.22.225.133) with Microsoft SMTP Server (TLS) id 14.3.248.2; Thu, 29 Oct 2015 01:00:15 -0700 Received: from orsmsx107.amr.corp.intel.com ([169.254.1.53]) by ORSMSX151.amr.corp.intel.com ([10.22.226.38]) with mapi id 14.03.0248.002; Thu, 29 Oct 2015 01:00:14 -0700 From: "Williams, Dan J" To: "torvalds@linux-foundation.org" , "akpm@linux-foundation.org" Subject: [GIT PULL] memremap fix for 4.3 Thread-Topic: [GIT PULL] memremap fix for 4.3 Thread-Index: AQHREh/X0Rx/YJVAD0CLTf223YwB6Q== Date: Thu, 29 Oct 2015 08:00:13 +0000 Message-ID: <1446105610.23766.17.camel@intel.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.22.254.140] Content-ID: <329119E3F08AEE448E84E3F9078BE6B2@intel.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151029_010044_991900_5D35FE6C X-CRM114-Status: GOOD ( 26.78 ) X-Spam-Score: -6.9 (------) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "rmk+kernel@arm.linux.org.uk" , "linux-kernel@vger.kernel.org" , "linux-arm-kernel@lists.infradead.org" , "ard.biesheuvel@linaro.org" Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Hi Linus, please pull from: git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm libnvdimm-fixes ...to receive a small fixlet for 4.3. The new memremap() api introduced in the 4.3 cycle to unify/replace ioremap_cache() and ioremap_wt() is mishandling the highmem case. This patch has received a build success notification from a 0day-kbuild-robot run and has been out for a review for a day. Russell has not had a chance to weigh in on it yet. I do not think the usage of kmap is strictly necessary as we should be able to fall back to ioremap_cache(), but I include it for two reasons: 1/ ARM ioremap() will WARN if passed a pfn_valid() address. 2/ acpi_map() carries a similar kmap fallback, and that quirk can now be centrally carried in this common routine. --- The following changes since commit 25cb62b76430a91cc6195f902e61c2cb84ade622: Linux 4.3-rc5 (2015-10-11 11:09:45 -0700) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm libnvdimm-fixes for you to fetch changes up to bcaa4236b558092dd5ff14ea943e89fd944fcd28: memremap: fix highmem support (2015-10-26 16:55:56 -0400) ---------------------------------------------------------------- Dan Williams (1): memremap: fix highmem support include/linux/highmem.h | 12 ++++++++++++ kernel/memremap.c | 28 +++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) commit bcaa4236b558092dd5ff14ea943e89fd944fcd28 Author: Dan Williams Date: Mon Oct 26 16:55:56 2015 -0400 memremap: fix highmem support Currently memremap checks if the range is "System RAM" and returns the kernel linear address. This is broken for highmem platforms where a range may be "System RAM", but is not part of the kernel linear mapping. Similar to acpi_map(), use kmap() for PAGE_SIZE memremap() requests for highmem, and fall back to ioremap_cache() otherwise. The impact of this bug is low for now since the pmem driver is the only user of memremap(), but this is important to fix before more conversions to memremap arrive in 4.4. Cc: Rafael J. Wysocki Reported-by: Ard Biesheuvel Signed-off-by: Dan Williams diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 6aefcd0031a6..c20cf24c76dd 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -41,6 +41,13 @@ void kmap_flush_unused(void); struct page *kmap_to_page(void *addr); +static inline bool is_kmap_addr(const void *x) +{ + unsigned long addr = (unsigned long) x; + + return addr >= PKMAP_ADDR(0) && addr < PKMAP_ADDR(LAST_PKMAP); +} + #else /* CONFIG_HIGHMEM */ static inline unsigned int nr_free_highpages(void) { return 0; } @@ -50,6 +57,11 @@ static inline struct page *kmap_to_page(void *addr) return virt_to_page(addr); } +static inline bool is_kmap_addr(const void *x) +{ + return false; +} + #define totalhigh_pages 0UL #ifndef ARCH_HAS_KMAP diff --git a/kernel/memremap.c b/kernel/memremap.c index 72b0c66628b6..901d7ec3583a 100644 --- a/kernel/memremap.c +++ b/kernel/memremap.c @@ -10,6 +10,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ +#include #include #include #include @@ -24,6 +25,25 @@ __weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long size) } #endif +static void *try_ram_remap(resource_size_t offset, size_t size) +{ + struct page *page = pfn_to_page(offset >> PAGE_SHIFT); + unsigned int pg_off = offset & ~PAGE_MASK; + + /* In the simple case just return the existing linear address */ + if (!PageHighMem(page)) + return __va(offset); + + /* + * Try kmap first since some arch ioremap implementations fail when + * being passed a ram address. + */ + if (pg_off + size <= PAGE_SIZE) + return kmap(page) + pg_off; + + return NULL; +} + /** * memremap() - remap an iomem_resource as cacheable memory * @offset: iomem resource start address @@ -66,8 +86,8 @@ void *memremap(resource_size_t offset, size_t size, unsigned long flags) * the requested range is potentially in "System RAM" */ if (is_ram == REGION_INTERSECTS) - addr = __va(offset); - else + addr = try_ram_remap(offset, size); + if (!addr) addr = ioremap_cache(offset, size); } @@ -94,7 +114,9 @@ EXPORT_SYMBOL(memremap); void memunmap(void *addr) { - if (is_vmalloc_addr(addr)) + if (is_kmap_addr(addr)) + kunmap(addr); + else if (is_vmalloc_addr(addr)) iounmap((void __iomem *) addr); } EXPORT_SYMBOL(memunmap);