Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm: add mmap_action_simple_ioremap()

Currently drivers use vm_iomap_memory() as a simple helper function for
I/O remapping memory over a range starting at a specified physical address
over a specified length.

In order to utilise this from mmap_prepare, separate out the core logic
into __simple_ioremap_prep(), update vm_iomap_memory() to use it, and add
simple_ioremap_prepare() to do the same with a VMA descriptor object.

We also add MMAP_SIMPLE_IO_REMAP and relevant fields to the struct
mmap_action type to permit this operation also.

We use mmap_action_ioremap() to set up the actual I/O remap operation once
we have checked and figured out the parameters, which makes
simple_ioremap_prepare() easy to implement.

We then add mmap_action_simple_ioremap() to allow drivers to make use of
this mode.

We update the mmap_prepare documentation to describe this mode. Finally,
we update the VMA tests to reflect this change.

Link: https://lkml.kernel.org/r/a08ef1c4542202684da63bb37f459d5dbbeddd91.1774045440.git.ljs@kernel.org
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
Reviewed-by: Suren Baghdasaryan <surenb@google.com>
Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Bodo Stroesser <bostroesser@gmail.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: David Hildenbrand <david@kernel.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Dexuan Cui <decui@microsoft.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Jann Horn <jannh@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: K. Y. Srinivasan <kys@microsoft.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Long Li <longli@microsoft.com>
Cc: Marc Dionne <marc.dionne@auristor.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Miquel Raynal <miquel.raynal@bootlin.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Richard Weinberger <richard@nod.at>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Vignesh Raghavendra <vigneshr@ti.com>
Cc: Wei Liu <wei.liu@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Lorenzo Stoakes (Oracle) and committed by
Andrew Morton
a1b7fb40 4995c67d

+102 -28
+3
Documentation/filesystems/mmap_prepare.rst
··· 153 153 * mmap_action_ioremap_full() - Same as mmap_action_ioremap(), only remaps 154 154 the entire mapping from ``start_pfn`` onward. 155 155 156 + * mmap_action_simple_ioremap() - Sets up an I/O remap from a specified 157 + physical address and over a specified length. 158 + 156 159 **NOTE:** The ``action`` field should never normally be manipulated directly, 157 160 rather you ought to use one of these helpers.
+23 -1
include/linux/mm.h
··· 4321 4321 * @start_pfn: The first PFN in the range to remap. 4322 4322 */ 4323 4323 static inline void mmap_action_ioremap_full(struct vm_area_desc *desc, 4324 - unsigned long start_pfn) 4324 + unsigned long start_pfn) 4325 4325 { 4326 4326 mmap_action_ioremap(desc, desc->start, start_pfn, vma_desc_size(desc)); 4327 + } 4328 + 4329 + /** 4330 + * mmap_action_simple_ioremap - helper for mmap_prepare hook to specify that the 4331 + * physical range in [start_phys_addr, start_phys_addr + size) should be I/O 4332 + * remapped. 4333 + * @desc: The VMA descriptor for the VMA requiring remap. 4334 + * @start_phys_addr: Start of the physical memory to be mapped. 4335 + * @size: Size of the area to map. 4336 + * 4337 + * NOTE: Some drivers might want to tweak desc->page_prot for purposes of 4338 + * write-combine or similar. 4339 + */ 4340 + static inline void mmap_action_simple_ioremap(struct vm_area_desc *desc, 4341 + phys_addr_t start_phys_addr, 4342 + unsigned long size) 4343 + { 4344 + struct mmap_action *action = &desc->action; 4345 + 4346 + action->simple_ioremap.start_phys_addr = start_phys_addr; 4347 + action->simple_ioremap.size = size; 4348 + action->type = MMAP_SIMPLE_IO_REMAP; 4327 4349 } 4328 4350 4329 4351 int mmap_action_prepare(struct vm_area_desc *desc);
+5 -1
include/linux/mm_types.h
··· 814 814 MMAP_NOTHING, /* Mapping is complete, no further action. */ 815 815 MMAP_REMAP_PFN, /* Remap PFN range. */ 816 816 MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */ 817 + MMAP_SIMPLE_IO_REMAP, /* I/O remap with guardrails. */ 817 818 }; 818 819 819 820 /* ··· 823 822 */ 824 823 struct mmap_action { 825 824 union { 826 - /* Remap range. */ 827 825 struct { 828 826 unsigned long start; 829 827 unsigned long start_pfn; 830 828 unsigned long size; 831 829 pgprot_t pgprot; 832 830 } remap; 831 + struct { 832 + phys_addr_t start_phys_addr; 833 + unsigned long size; 834 + } simple_ioremap; 833 835 }; 834 836 enum mmap_action_type type; 835 837
+1
mm/internal.h
··· 1842 1842 int remap_pfn_range_prepare(struct vm_area_desc *desc); 1843 1843 int remap_pfn_range_complete(struct vm_area_struct *vma, 1844 1844 struct mmap_action *action); 1845 + int simple_ioremap_prepare(struct vm_area_desc *desc); 1845 1846 1846 1847 static inline int io_remap_pfn_range_prepare(struct vm_area_desc *desc) 1847 1848 {
+60 -25
mm/memory.c
··· 3170 3170 return do_remap_pfn_range(vma, start, pfn, size, prot); 3171 3171 } 3172 3172 3173 + static int __simple_ioremap_prep(unsigned long vm_len, pgoff_t vm_pgoff, 3174 + phys_addr_t start_phys, unsigned long size, 3175 + unsigned long *pfnp) 3176 + { 3177 + unsigned long pfn, pages; 3178 + 3179 + /* Check that the physical memory area passed in looks valid */ 3180 + if (start_phys + size < start_phys) 3181 + return -EINVAL; 3182 + /* 3183 + * You *really* shouldn't map things that aren't page-aligned, 3184 + * but we've historically allowed it because IO memory might 3185 + * just have smaller alignment. 3186 + */ 3187 + size += start_phys & ~PAGE_MASK; 3188 + pfn = start_phys >> PAGE_SHIFT; 3189 + pages = (size + ~PAGE_MASK) >> PAGE_SHIFT; 3190 + if (pfn + pages < pfn) 3191 + return -EINVAL; 3192 + 3193 + /* We start the mapping 'vm_pgoff' pages into the area */ 3194 + if (vm_pgoff > pages) 3195 + return -EINVAL; 3196 + pfn += vm_pgoff; 3197 + pages -= vm_pgoff; 3198 + 3199 + /* Can we fit all of the mapping? */ 3200 + if ((vm_len >> PAGE_SHIFT) > pages) 3201 + return -EINVAL; 3202 + 3203 + *pfnp = pfn; 3204 + return 0; 3205 + } 3206 + 3207 + int simple_ioremap_prepare(struct vm_area_desc *desc) 3208 + { 3209 + struct mmap_action *action = &desc->action; 3210 + const phys_addr_t start = action->simple_ioremap.start_phys_addr; 3211 + const unsigned long size = action->simple_ioremap.size; 3212 + unsigned long pfn; 3213 + int err; 3214 + 3215 + err = __simple_ioremap_prep(vma_desc_size(desc), desc->pgoff, 3216 + start, size, &pfn); 3217 + if (err) 3218 + return err; 3219 + 3220 + /* The I/O remap logic does the heavy lifting. */ 3221 + mmap_action_ioremap_full(desc, pfn); 3222 + return io_remap_pfn_range_prepare(desc); 3223 + } 3224 + 3173 3225 /** 3174 3226 * vm_iomap_memory - remap memory to userspace 3175 3227 * @vma: user vma to map to ··· 3239 3187 */ 3240 3188 int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len) 3241 3189 { 3242 - unsigned long vm_len, pfn, pages; 3190 + const unsigned long vm_start = vma->vm_start; 3191 + const unsigned long vm_end = vma->vm_end; 3192 + const unsigned long vm_len = vm_end - vm_start; 3193 + unsigned long pfn; 3194 + int err; 3243 3195 3244 - /* Check that the physical memory area passed in looks valid */ 3245 - if (start + len < start) 3246 - return -EINVAL; 3247 - /* 3248 - * You *really* shouldn't map things that aren't page-aligned, 3249 - * but we've historically allowed it because IO memory might 3250 - * just have smaller alignment. 3251 - */ 3252 - len += start & ~PAGE_MASK; 3253 - pfn = start >> PAGE_SHIFT; 3254 - pages = (len + ~PAGE_MASK) >> PAGE_SHIFT; 3255 - if (pfn + pages < pfn) 3256 - return -EINVAL; 3257 - 3258 - /* We start the mapping 'vm_pgoff' pages into the area */ 3259 - if (vma->vm_pgoff > pages) 3260 - return -EINVAL; 3261 - pfn += vma->vm_pgoff; 3262 - pages -= vma->vm_pgoff; 3263 - 3264 - /* Can we fit all of the mapping? */ 3265 - vm_len = vma->vm_end - vma->vm_start; 3266 - if (vm_len >> PAGE_SHIFT > pages) 3267 - return -EINVAL; 3196 + err = __simple_ioremap_prep(vm_len, vma->vm_pgoff, start, len, &pfn); 3197 + if (err) 3198 + return err; 3268 3199 3269 3200 /* Ok, let it rip */ 3270 3201 return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
+5
mm/util.c
··· 1393 1393 return remap_pfn_range_prepare(desc); 1394 1394 case MMAP_IO_REMAP_PFN: 1395 1395 return io_remap_pfn_range_prepare(desc); 1396 + case MMAP_SIMPLE_IO_REMAP: 1397 + return simple_ioremap_prepare(desc); 1396 1398 } 1397 1399 1398 1400 WARN_ON_ONCE(1); ··· 1423 1421 err = remap_pfn_range_complete(vma, action); 1424 1422 break; 1425 1423 case MMAP_IO_REMAP_PFN: 1424 + case MMAP_SIMPLE_IO_REMAP: 1426 1425 /* Should have been delegated. */ 1427 1426 WARN_ON_ONCE(1); 1428 1427 err = -EINVAL; ··· 1441 1438 break; 1442 1439 case MMAP_REMAP_PFN: 1443 1440 case MMAP_IO_REMAP_PFN: 1441 + case MMAP_SIMPLE_IO_REMAP: 1444 1442 WARN_ON_ONCE(1); /* nommu cannot handle these. */ 1445 1443 break; 1446 1444 } ··· 1460 1456 break; 1461 1457 case MMAP_REMAP_PFN: 1462 1458 case MMAP_IO_REMAP_PFN: 1459 + case MMAP_SIMPLE_IO_REMAP: 1463 1460 WARN_ON_ONCE(1); /* nommu cannot handle this. */ 1464 1461 1465 1462 err = -EINVAL;
+5 -1
tools/testing/vma/include/dup.h
··· 453 453 MMAP_NOTHING, /* Mapping is complete, no further action. */ 454 454 MMAP_REMAP_PFN, /* Remap PFN range. */ 455 455 MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */ 456 + MMAP_SIMPLE_IO_REMAP, /* I/O remap with guardrails. */ 456 457 }; 457 458 458 459 /* ··· 462 461 */ 463 462 struct mmap_action { 464 463 union { 465 - /* Remap range. */ 466 464 struct { 467 465 unsigned long start; 468 466 unsigned long start_pfn; 469 467 unsigned long size; 470 468 pgprot_t pgprot; 471 469 } remap; 470 + struct { 471 + phys_addr_t start_phys_addr; 472 + unsigned long size; 473 + } simple_ioremap; 472 474 }; 473 475 enum mmap_action_type type; 474 476