From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 15E042096AEE3 for ; Wed, 9 May 2018 03:29:14 -0700 (PDT) Date: Wed, 9 May 2018 12:29:11 +0200 From: Jan Kara Subject: Re: [PATCH v9 3/9] memremap: split devm_memremap_pages() and memremap() infrastructure Message-ID: <20180509102911.fqr7p3urcsielgqo@quack2.suse.cz> References: <152461278149.17530.2867511144531572045.stgit@dwillia2-desk3.amr.corp.intel.com> <152461279892.17530.9006728553718402327.stgit@dwillia2-desk3.amr.corp.intel.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <152461279892.17530.9006728553718402327.stgit@dwillia2-desk3.amr.corp.intel.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Errors-To: linux-nvdimm-bounces@lists.01.org Sender: "Linux-nvdimm" To: Dan Williams Cc: Jan Kara , linux-nvdimm@lists.01.org, david@fromorbit.com, linux-xfs@vger.kernel.org, linux-mm@kvack.org, =?iso-8859-1?B?Suly9G1l?= Glisse , linux-fsdevel@vger.kernel.org, Christoph Hellwig List-ID: On Tue 24-04-18 16:33:19, Dan Williams wrote: > Currently, kernel/memremap.c contains generic code for supporting > memremap() (CONFIG_HAS_IOMEM) and devm_memremap_pages() > (CONFIG_ZONE_DEVICE). This causes ongoing build maintenance problems as > additions to memremap.c, especially for the ZONE_DEVICE case, need to be > careful about being placed in ifdef guards. Remove the need for these > ifdef guards by moving the ZONE_DEVICE support functions to their own > compilation unit. > = > Cc: Jan Kara > Cc: Christoph Hellwig > Cc: "J=E9r=F4me Glisse" > Cc: Ross Zwisler > Signed-off-by: Dan Williams Good idea. You can add: Reviewed-by: Jan Kara Honza > --- > kernel/Makefile | 3 + > kernel/iomem.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++= +++ > kernel/memremap.c | 178 +----------------------------------------------= ------ > 3 files changed, 171 insertions(+), 177 deletions(-) > create mode 100644 kernel/iomem.c > = > diff --git a/kernel/Makefile b/kernel/Makefile > index f85ae5dfa474..9b9241361311 100644 > --- a/kernel/Makefile > +++ b/kernel/Makefile > @@ -112,7 +112,8 @@ obj-$(CONFIG_JUMP_LABEL) +=3D jump_label.o > obj-$(CONFIG_CONTEXT_TRACKING) +=3D context_tracking.o > obj-$(CONFIG_TORTURE_TEST) +=3D torture.o > = > -obj-$(CONFIG_HAS_IOMEM) +=3D memremap.o > +obj-$(CONFIG_HAS_IOMEM) +=3D iomem.o > +obj-$(CONFIG_ZONE_DEVICE) +=3D memremap.o > = > $(obj)/configs.o: $(obj)/config_data.h > = > diff --git a/kernel/iomem.c b/kernel/iomem.c > new file mode 100644 > index 000000000000..f7525e14ebc6 > --- /dev/null > +++ b/kernel/iomem.c > @@ -0,0 +1,167 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#include > +#include > +#include > +#include > + > +#ifndef ioremap_cache > +/* temporary while we convert existing ioremap_cache users to memremap */ > +__weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long= size) > +{ > + return ioremap(offset, size); > +} > +#endif > + > +#ifndef arch_memremap_wb > +static void *arch_memremap_wb(resource_size_t offset, unsigned long size) > +{ > + return (__force void *)ioremap_cache(offset, size); > +} > +#endif > + > +#ifndef arch_memremap_can_ram_remap > +static bool arch_memremap_can_ram_remap(resource_size_t offset, size_t s= ize, > + unsigned long flags) > +{ > + return true; > +} > +#endif > + > +static void *try_ram_remap(resource_size_t offset, size_t size, > + unsigned long flags) > +{ > + unsigned long pfn =3D PHYS_PFN(offset); > + > + /* In the simple case just return the existing linear address */ > + if (pfn_valid(pfn) && !PageHighMem(pfn_to_page(pfn)) && > + arch_memremap_can_ram_remap(offset, size, flags)) > + return __va(offset); > + > + return NULL; /* fallback to arch_memremap_wb */ > +} > + > +/** > + * memremap() - remap an iomem_resource as cacheable memory > + * @offset: iomem resource start address > + * @size: size of remap > + * @flags: any of MEMREMAP_WB, MEMREMAP_WT, MEMREMAP_WC, > + * MEMREMAP_ENC, MEMREMAP_DEC > + * > + * memremap() is "ioremap" for cases where it is known that the resource > + * being mapped does not have i/o side effects and the __iomem > + * annotation is not applicable. In the case of multiple flags, the diff= erent > + * mapping types will be attempted in the order listed below until one of > + * them succeeds. > + * > + * MEMREMAP_WB - matches the default mapping for System RAM on > + * the architecture. This is usually a read-allocate write-back cache. > + * Morever, if MEMREMAP_WB is specified and the requested remap region i= s RAM > + * memremap() will bypass establishing a new mapping and instead return > + * a pointer into the direct map. > + * > + * MEMREMAP_WT - establish a mapping whereby writes either bypass the > + * cache or are written through to memory and never exist in a > + * cache-dirty state with respect to program visibility. Attempts to > + * map System RAM with this mapping type will fail. > + * > + * MEMREMAP_WC - establish a writecombine mapping, whereby writes may > + * be coalesced together (e.g. in the CPU's write buffers), but is other= wise > + * uncached. Attempts to map System RAM with this mapping type will fail. > + */ > +void *memremap(resource_size_t offset, size_t size, unsigned long flags) > +{ > + int is_ram =3D region_intersects(offset, size, > + IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE); > + void *addr =3D NULL; > + > + if (!flags) > + return NULL; > + > + if (is_ram =3D=3D REGION_MIXED) { > + WARN_ONCE(1, "memremap attempted on mixed range %pa size: %#lx\n", > + &offset, (unsigned long) size); > + return NULL; > + } > + > + /* Try all mapping types requested until one returns non-NULL */ > + if (flags & MEMREMAP_WB) { > + /* > + * MEMREMAP_WB is special in that it can be satisifed > + * from the direct map. Some archs depend on the > + * capability of memremap() to autodetect cases where > + * the requested range is potentially in System RAM. > + */ > + if (is_ram =3D=3D REGION_INTERSECTS) > + addr =3D try_ram_remap(offset, size, flags); > + if (!addr) > + addr =3D arch_memremap_wb(offset, size); > + } > + > + /* > + * If we don't have a mapping yet and other request flags are > + * present then we will be attempting to establish a new virtual > + * address mapping. Enforce that this mapping is not aliasing > + * System RAM. > + */ > + if (!addr && is_ram =3D=3D REGION_INTERSECTS && flags !=3D MEMREMAP_WB)= { > + WARN_ONCE(1, "memremap attempted on ram %pa size: %#lx\n", > + &offset, (unsigned long) size); > + return NULL; > + } > + > + if (!addr && (flags & MEMREMAP_WT)) > + addr =3D ioremap_wt(offset, size); > + > + if (!addr && (flags & MEMREMAP_WC)) > + addr =3D ioremap_wc(offset, size); > + > + return addr; > +} > +EXPORT_SYMBOL(memremap); > + > +void memunmap(void *addr) > +{ > + if (is_vmalloc_addr(addr)) > + iounmap((void __iomem *) addr); > +} > +EXPORT_SYMBOL(memunmap); > + > +static void devm_memremap_release(struct device *dev, void *res) > +{ > + memunmap(*(void **)res); > +} > + > +static int devm_memremap_match(struct device *dev, void *res, void *matc= h_data) > +{ > + return *(void **)res =3D=3D match_data; > +} > + > +void *devm_memremap(struct device *dev, resource_size_t offset, > + size_t size, unsigned long flags) > +{ > + void **ptr, *addr; > + > + ptr =3D devres_alloc_node(devm_memremap_release, sizeof(*ptr), GFP_KERN= EL, > + dev_to_node(dev)); > + if (!ptr) > + return ERR_PTR(-ENOMEM); > + > + addr =3D memremap(offset, size, flags); > + if (addr) { > + *ptr =3D addr; > + devres_add(dev, ptr); > + } else { > + devres_free(ptr); > + return ERR_PTR(-ENXIO); > + } > + > + return addr; > +} > +EXPORT_SYMBOL(devm_memremap); > + > +void devm_memunmap(struct device *dev, void *addr) > +{ > + WARN_ON(devres_release(dev, devm_memremap_release, > + devm_memremap_match, addr)); > +} > +EXPORT_SYMBOL(devm_memunmap); > diff --git a/kernel/memremap.c b/kernel/memremap.c > index 895e6b76b25e..37a9604133f6 100644 > --- a/kernel/memremap.c > +++ b/kernel/memremap.c > @@ -1,15 +1,5 @@ > -/* > - * Copyright(c) 2015 Intel Corporation. All rights reserved. > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of version 2 of the GNU General Public License as > - * published by the Free Software Foundation. > - * > - * This program is distributed in the hope that it will be useful, but > - * WITHOUT ANY WARRANTY; without even the implied warranty of > - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > - * General Public License for more details. > - */ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* Copyright(c) 2015 Intel Corporation. All rights reserved. */ > #include > #include > #include > @@ -20,169 +10,6 @@ > #include > #include > = > -#ifndef ioremap_cache > -/* temporary while we convert existing ioremap_cache users to memremap */ > -__weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long= size) > -{ > - return ioremap(offset, size); > -} > -#endif > - > -#ifndef arch_memremap_wb > -static void *arch_memremap_wb(resource_size_t offset, unsigned long size) > -{ > - return (__force void *)ioremap_cache(offset, size); > -} > -#endif > - > -#ifndef arch_memremap_can_ram_remap > -static bool arch_memremap_can_ram_remap(resource_size_t offset, size_t s= ize, > - unsigned long flags) > -{ > - return true; > -} > -#endif > - > -static void *try_ram_remap(resource_size_t offset, size_t size, > - unsigned long flags) > -{ > - unsigned long pfn =3D PHYS_PFN(offset); > - > - /* In the simple case just return the existing linear address */ > - if (pfn_valid(pfn) && !PageHighMem(pfn_to_page(pfn)) && > - arch_memremap_can_ram_remap(offset, size, flags)) > - return __va(offset); > - > - return NULL; /* fallback to arch_memremap_wb */ > -} > - > -/** > - * memremap() - remap an iomem_resource as cacheable memory > - * @offset: iomem resource start address > - * @size: size of remap > - * @flags: any of MEMREMAP_WB, MEMREMAP_WT, MEMREMAP_WC, > - * MEMREMAP_ENC, MEMREMAP_DEC > - * > - * memremap() is "ioremap" for cases where it is known that the resource > - * being mapped does not have i/o side effects and the __iomem > - * annotation is not applicable. In the case of multiple flags, the diff= erent > - * mapping types will be attempted in the order listed below until one of > - * them succeeds. > - * > - * MEMREMAP_WB - matches the default mapping for System RAM on > - * the architecture. This is usually a read-allocate write-back cache. > - * Morever, if MEMREMAP_WB is specified and the requested remap region i= s RAM > - * memremap() will bypass establishing a new mapping and instead return > - * a pointer into the direct map. > - * > - * MEMREMAP_WT - establish a mapping whereby writes either bypass the > - * cache or are written through to memory and never exist in a > - * cache-dirty state with respect to program visibility. Attempts to > - * map System RAM with this mapping type will fail. > - * > - * MEMREMAP_WC - establish a writecombine mapping, whereby writes may > - * be coalesced together (e.g. in the CPU's write buffers), but is other= wise > - * uncached. Attempts to map System RAM with this mapping type will fail. > - */ > -void *memremap(resource_size_t offset, size_t size, unsigned long flags) > -{ > - int is_ram =3D region_intersects(offset, size, > - IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE); > - void *addr =3D NULL; > - > - if (!flags) > - return NULL; > - > - if (is_ram =3D=3D REGION_MIXED) { > - WARN_ONCE(1, "memremap attempted on mixed range %pa size: %#lx\n", > - &offset, (unsigned long) size); > - return NULL; > - } > - > - /* Try all mapping types requested until one returns non-NULL */ > - if (flags & MEMREMAP_WB) { > - /* > - * MEMREMAP_WB is special in that it can be satisifed > - * from the direct map. Some archs depend on the > - * capability of memremap() to autodetect cases where > - * the requested range is potentially in System RAM. > - */ > - if (is_ram =3D=3D REGION_INTERSECTS) > - addr =3D try_ram_remap(offset, size, flags); > - if (!addr) > - addr =3D arch_memremap_wb(offset, size); > - } > - > - /* > - * If we don't have a mapping yet and other request flags are > - * present then we will be attempting to establish a new virtual > - * address mapping. Enforce that this mapping is not aliasing > - * System RAM. > - */ > - if (!addr && is_ram =3D=3D REGION_INTERSECTS && flags !=3D MEMREMAP_WB)= { > - WARN_ONCE(1, "memremap attempted on ram %pa size: %#lx\n", > - &offset, (unsigned long) size); > - return NULL; > - } > - > - if (!addr && (flags & MEMREMAP_WT)) > - addr =3D ioremap_wt(offset, size); > - > - if (!addr && (flags & MEMREMAP_WC)) > - addr =3D ioremap_wc(offset, size); > - > - return addr; > -} > -EXPORT_SYMBOL(memremap); > - > -void memunmap(void *addr) > -{ > - if (is_vmalloc_addr(addr)) > - iounmap((void __iomem *) addr); > -} > -EXPORT_SYMBOL(memunmap); > - > -static void devm_memremap_release(struct device *dev, void *res) > -{ > - memunmap(*(void **)res); > -} > - > -static int devm_memremap_match(struct device *dev, void *res, void *matc= h_data) > -{ > - return *(void **)res =3D=3D match_data; > -} > - > -void *devm_memremap(struct device *dev, resource_size_t offset, > - size_t size, unsigned long flags) > -{ > - void **ptr, *addr; > - > - ptr =3D devres_alloc_node(devm_memremap_release, sizeof(*ptr), GFP_KERN= EL, > - dev_to_node(dev)); > - if (!ptr) > - return ERR_PTR(-ENOMEM); > - > - addr =3D memremap(offset, size, flags); > - if (addr) { > - *ptr =3D addr; > - devres_add(dev, ptr); > - } else { > - devres_free(ptr); > - return ERR_PTR(-ENXIO); > - } > - > - return addr; > -} > -EXPORT_SYMBOL(devm_memremap); > - > -void devm_memunmap(struct device *dev, void *addr) > -{ > - WARN_ON(devres_release(dev, devm_memremap_release, > - devm_memremap_match, addr)); > -} > -EXPORT_SYMBOL(devm_memunmap); > - > -#ifdef CONFIG_ZONE_DEVICE > static DEFINE_MUTEX(pgmap_lock); > static RADIX_TREE(pgmap_radix, GFP_KERNEL); > #define SECTION_MASK ~((1UL << PA_SECTION_SHIFT) - 1) > @@ -473,7 +300,6 @@ struct dev_pagemap *get_dev_pagemap(unsigned long pfn, > = > return pgmap; > } > -#endif /* CONFIG_ZONE_DEVICE */ > = > #if IS_ENABLED(CONFIG_DEVICE_PRIVATE) || IS_ENABLED(CONFIG_DEVICE_PUBLI= C) > void put_zone_device_private_or_public_page(struct page *page) > = -- = Jan Kara SUSE Labs, CR _______________________________________________ Linux-nvdimm mailing list Linux-nvdimm@lists.01.org https://lists.01.org/mailman/listinfo/linux-nvdimm