1 1.1 riastrad /* $NetBSD: i915_mm.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2014 Intel Corporation 5 1.1 riastrad * 6 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 7 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 8 1.1 riastrad * to deal in the Software without restriction, including without limitation 9 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 11 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 12 1.1 riastrad * 13 1.1 riastrad * The above copyright notice and this permission notice (including the next 14 1.1 riastrad * paragraph) shall be included in all copies or substantial portions of the 15 1.1 riastrad * Software. 16 1.1 riastrad * 17 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 1.1 riastrad * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 1.1 riastrad * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 1.1 riastrad * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 1.1 riastrad * IN THE SOFTWARE. 24 1.1 riastrad * 25 1.1 riastrad */ 26 1.1 riastrad 27 1.1 riastrad #include <sys/cdefs.h> 28 1.1 riastrad __KERNEL_RCSID(0, "$NetBSD: i915_mm.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $"); 29 1.1 riastrad 30 1.1 riastrad #include <linux/mm.h> 31 1.1 riastrad #include <linux/io-mapping.h> 32 1.1 riastrad 33 1.1 riastrad #include <asm/pgtable.h> 34 1.1 riastrad 35 1.1 riastrad #include "i915_drv.h" 36 1.1 riastrad 37 1.1 riastrad struct remap_pfn { 38 1.1 riastrad struct mm_struct *mm; 39 1.1 riastrad unsigned long pfn; 40 1.1 riastrad pgprot_t prot; 41 1.1 riastrad 42 1.1 riastrad struct sgt_iter sgt; 43 1.1 riastrad resource_size_t iobase; 44 1.1 riastrad }; 45 1.1 riastrad 46 1.1 riastrad static int remap_pfn(pte_t *pte, unsigned long addr, void *data) 47 1.1 riastrad { 48 1.1 riastrad struct remap_pfn *r = data; 49 1.1 riastrad 50 1.1 riastrad /* Special PTE are not associated with any struct page */ 51 1.1 riastrad set_pte_at(r->mm, addr, pte, pte_mkspecial(pfn_pte(r->pfn, r->prot))); 52 1.1 riastrad r->pfn++; 53 1.1 riastrad 54 1.1 riastrad return 0; 55 1.1 riastrad } 56 1.1 riastrad 57 1.1 riastrad #define use_dma(io) ((io) != -1) 58 1.1 riastrad 59 1.1 riastrad static inline unsigned long sgt_pfn(const struct remap_pfn *r) 60 1.1 riastrad { 61 1.1 riastrad if (use_dma(r->iobase)) 62 1.1 riastrad return (r->sgt.dma + r->sgt.curr + r->iobase) >> PAGE_SHIFT; 63 1.1 riastrad else 64 1.1 riastrad return r->sgt.pfn + (r->sgt.curr >> PAGE_SHIFT); 65 1.1 riastrad } 66 1.1 riastrad 67 1.1 riastrad static int remap_sg(pte_t *pte, unsigned long addr, void *data) 68 1.1 riastrad { 69 1.1 riastrad struct remap_pfn *r = data; 70 1.1 riastrad 71 1.1 riastrad if (GEM_WARN_ON(!r->sgt.pfn)) 72 1.1 riastrad return -EINVAL; 73 1.1 riastrad 74 1.1 riastrad /* Special PTE are not associated with any struct page */ 75 1.1 riastrad set_pte_at(r->mm, addr, pte, 76 1.1 riastrad pte_mkspecial(pfn_pte(sgt_pfn(r), r->prot))); 77 1.1 riastrad r->pfn++; /* track insertions in case we need to unwind later */ 78 1.1 riastrad 79 1.1 riastrad r->sgt.curr += PAGE_SIZE; 80 1.1 riastrad if (r->sgt.curr >= r->sgt.max) 81 1.1 riastrad r->sgt = __sgt_iter(__sg_next(r->sgt.sgp), use_dma(r->iobase)); 82 1.1 riastrad 83 1.1 riastrad return 0; 84 1.1 riastrad } 85 1.1 riastrad 86 1.1 riastrad /** 87 1.1 riastrad * remap_io_mapping - remap an IO mapping to userspace 88 1.1 riastrad * @vma: user vma to map to 89 1.1 riastrad * @addr: target user address to start at 90 1.1 riastrad * @pfn: physical address of kernel memory 91 1.1 riastrad * @size: size of map area 92 1.1 riastrad * @iomap: the source io_mapping 93 1.1 riastrad * 94 1.1 riastrad * Note: this is only safe if the mm semaphore is held when called. 95 1.1 riastrad */ 96 1.1 riastrad int remap_io_mapping(struct vm_area_struct *vma, 97 1.1 riastrad unsigned long addr, unsigned long pfn, unsigned long size, 98 1.1 riastrad struct io_mapping *iomap) 99 1.1 riastrad { 100 1.1 riastrad struct remap_pfn r; 101 1.1 riastrad int err; 102 1.1 riastrad 103 1.1 riastrad #define EXPECTED_FLAGS (VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP) 104 1.1 riastrad GEM_BUG_ON((vma->vm_flags & EXPECTED_FLAGS) != EXPECTED_FLAGS); 105 1.1 riastrad 106 1.1 riastrad /* We rely on prevalidation of the io-mapping to skip track_pfn(). */ 107 1.1 riastrad r.mm = vma->vm_mm; 108 1.1 riastrad r.pfn = pfn; 109 1.1 riastrad r.prot = __pgprot((pgprot_val(iomap->prot) & _PAGE_CACHE_MASK) | 110 1.1 riastrad (pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK)); 111 1.1 riastrad 112 1.1 riastrad err = apply_to_page_range(r.mm, addr, size, remap_pfn, &r); 113 1.1 riastrad if (unlikely(err)) { 114 1.1 riastrad zap_vma_ptes(vma, addr, (r.pfn - pfn) << PAGE_SHIFT); 115 1.1 riastrad return err; 116 1.1 riastrad } 117 1.1 riastrad 118 1.1 riastrad return 0; 119 1.1 riastrad } 120 1.1 riastrad 121 1.1 riastrad /** 122 1.1 riastrad * remap_io_sg - remap an IO mapping to userspace 123 1.1 riastrad * @vma: user vma to map to 124 1.1 riastrad * @addr: target user address to start at 125 1.1 riastrad * @size: size of map area 126 1.1 riastrad * @sgl: Start sg entry 127 1.1 riastrad * @iobase: Use stored dma address offset by this address or pfn if -1 128 1.1 riastrad * 129 1.1 riastrad * Note: this is only safe if the mm semaphore is held when called. 130 1.1 riastrad */ 131 1.1 riastrad int remap_io_sg(struct vm_area_struct *vma, 132 1.1 riastrad unsigned long addr, unsigned long size, 133 1.1 riastrad struct scatterlist *sgl, resource_size_t iobase) 134 1.1 riastrad { 135 1.1 riastrad struct remap_pfn r = { 136 1.1 riastrad .mm = vma->vm_mm, 137 1.1 riastrad .prot = vma->vm_page_prot, 138 1.1 riastrad .sgt = __sgt_iter(sgl, use_dma(iobase)), 139 1.1 riastrad .iobase = iobase, 140 1.1 riastrad }; 141 1.1 riastrad int err; 142 1.1 riastrad 143 1.1 riastrad /* We rely on prevalidation of the io-mapping to skip track_pfn(). */ 144 1.1 riastrad GEM_BUG_ON((vma->vm_flags & EXPECTED_FLAGS) != EXPECTED_FLAGS); 145 1.1 riastrad 146 1.1 riastrad if (!use_dma(iobase)) 147 1.1 riastrad flush_cache_range(vma, addr, size); 148 1.1 riastrad 149 1.1 riastrad err = apply_to_page_range(r.mm, addr, size, remap_sg, &r); 150 1.1 riastrad if (unlikely(err)) { 151 1.1 riastrad zap_vma_ptes(vma, addr, r.pfn << PAGE_SHIFT); 152 1.1 riastrad return err; 153 1.1 riastrad } 154 1.1 riastrad 155 1.1 riastrad return 0; 156 1.1 riastrad } 157