1 /* $NetBSD: i915_gem_phys.c,v 1.9 2024/01/19 22:23:04 riastradh Exp $ */ 2 3 /* 4 * SPDX-License-Identifier: MIT 5 * 6 * Copyright 2014-2016 Intel Corporation 7 */ 8 9 #include <sys/cdefs.h> 10 __KERNEL_RCSID(0, "$NetBSD: i915_gem_phys.c,v 1.9 2024/01/19 22:23:04 riastradh Exp $"); 11 12 #ifdef __NetBSD__ 13 /* 14 * Make sure this block comes before any linux includes, so we don't 15 * get mixed up by the PAGE_MASK complementation. 16 */ 17 18 #include <sys/bus.h> 19 20 #include <uvm/uvm.h> 21 #include <uvm/uvm_extern.h> 22 23 #include <machine/pmap_private.h> /* kvtopte, pmap_pte_clearbits */ 24 25 /* 26 * Version of bus_dmamem_map that uses pmap_kenter_pa, not pmap_enter, 27 * so that it isn't affected by pmap_page_protect on the physical 28 * address. Adapted from sys/arch/x86/x86/bus_dma.c. 29 */ 30 static int 31 bus_dmamem_kmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 32 size_t size, void **kvap, int flags) 33 { 34 vaddr_t va; 35 bus_addr_t addr; 36 int curseg; 37 const uvm_flag_t kmflags = 38 (flags & BUS_DMA_NOWAIT) != 0 ? UVM_KMF_NOWAIT : 0; 39 u_int pmapflags = PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE; 40 41 size = round_page(size); 42 if (flags & BUS_DMA_NOCACHE) 43 pmapflags |= PMAP_NOCACHE; 44 45 va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY | kmflags); 46 47 if (va == 0) 48 return ENOMEM; 49 50 *kvap = (void *)va; 51 52 for (curseg = 0; curseg < nsegs; curseg++) { 53 for (addr = segs[curseg].ds_addr; 54 addr < (segs[curseg].ds_addr + segs[curseg].ds_len); 55 addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) { 56 if (size == 0) 57 panic("bus_dmamem_kmap: size botch"); 58 pmap_kenter_pa(va, addr, 59 VM_PROT_READ | VM_PROT_WRITE, 60 pmapflags); 61 } 62 } 63 pmap_update(pmap_kernel()); 64 65 return 0; 66 } 67 68 static void 69 bus_dmamem_kunmap(bus_dma_tag_t t, void *kva, size_t size) 70 { 71 pt_entry_t *pte, opte; 72 vaddr_t va, sva, eva; 73 74 KASSERTMSG(((uintptr_t)kva & PGOFSET) == 0, "kva=%p", kva); 75 76 size = round_page(size); 77 sva = (vaddr_t)kva; 78 eva = sva + size; 79 80 /* 81 * mark pages cacheable again. 82 */ 83 for (va = sva; va < eva; va += PAGE_SIZE) { 84 pte = kvtopte(va); 85 opte = *pte; 86 if ((opte & PTE_PCD) != 0) 87 pmap_pte_clearbits(pte, PTE_PCD); 88 } 89 pmap_kremove((vaddr_t)kva, size); 90 pmap_update(pmap_kernel()); 91 uvm_km_free(kernel_map, (vaddr_t)kva, size, UVM_KMF_VAONLY); 92 } 93 94 #endif 95 96 #include <linux/highmem.h> 97 #include <linux/shmem_fs.h> 98 #include <linux/swap.h> 99 100 #include <drm/drm.h> /* for drm_legacy.h! */ 101 #include <drm/drm_cache.h> 102 #include <drm/drm_legacy.h> /* for drm_pci.h! */ 103 #include <drm/drm_pci.h> 104 105 #include "gt/intel_gt.h" 106 #include "i915_drv.h" 107 #include "i915_gem_object.h" 108 #include "i915_gem_region.h" 109 #include "i915_scatterlist.h" 110 111 #include <linux/nbsd-namespace.h> 112 113 static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) 114 { 115 #ifdef __NetBSD__ 116 struct uvm_object *mapping = obj->base.filp; 117 #else 118 struct address_space *mapping = obj->base.filp->f_mapping; 119 #endif 120 struct scatterlist *sg; 121 struct sg_table *st; 122 dma_addr_t dma; 123 void *vaddr; 124 void *dst; 125 int i; 126 127 if (WARN_ON(i915_gem_object_needs_bit17_swizzle(obj))) 128 return -EINVAL; 129 130 131 /* 132 * Always aligning to the object size, allows a single allocation 133 * to handle all possible callers, and given typical object sizes, 134 * the alignment of the buddy allocation will naturally match. 135 */ 136 #ifdef __NetBSD__ 137 __USE(dma); 138 bus_dma_tag_t dmat = obj->base.dev->dmat; 139 bool loaded = false; 140 int rsegs = 0; 141 int ret; 142 143 vaddr = NULL; 144 145 /* XXX errno NetBSD->Linux */ 146 ret = -bus_dmamem_alloc(dmat, roundup_pow_of_two(obj->base.size), 147 roundup_pow_of_two(obj->base.size), 0, &obj->mm.u.phys.seg, 1, 148 &rsegs, BUS_DMA_WAITOK); 149 if (ret) 150 return -ENOMEM; 151 KASSERT(rsegs == 1); 152 ret = -bus_dmamem_kmap(dmat, &obj->mm.u.phys.seg, 1, 153 roundup_pow_of_two(obj->base.size), &vaddr, 154 BUS_DMA_WAITOK|BUS_DMA_COHERENT); 155 if (ret) 156 goto err_pci; 157 obj->mm.u.phys.kva = vaddr; 158 #else 159 vaddr = dma_alloc_coherent(&obj->base.dev->pdev->dev, 160 roundup_pow_of_two(obj->base.size), 161 &dma, GFP_KERNEL); 162 if (!vaddr) 163 return -ENOMEM; 164 #endif 165 166 st = kmalloc(sizeof(*st), GFP_KERNEL); 167 if (!st) 168 goto err_pci; 169 170 #ifdef __NetBSD__ 171 if (sg_alloc_table_from_bus_dmamem(st, dmat, &obj->mm.u.phys.seg, 1, 172 GFP_KERNEL)) 173 #else 174 if (sg_alloc_table(st, 1, GFP_KERNEL)) 175 #endif 176 goto err_st; 177 178 sg = st->sgl; 179 #ifdef __NetBSD__ 180 /* XXX errno NetBSD->Linux */ 181 ret = -bus_dmamap_create(dmat, roundup_pow_of_two(obj->base.size), 1, 182 roundup_pow_of_two(obj->base.size), 0, BUS_DMA_WAITOK, 183 &sg->sg_dmamap); 184 if (ret) { 185 sg->sg_dmamap = NULL; 186 goto err_st1; 187 } 188 sg->sg_dmat = dmat; 189 /* XXX errno NetBSD->Linux */ 190 ret = -bus_dmamap_load_raw(dmat, sg->sg_dmamap, &obj->mm.u.phys.seg, 1, 191 roundup_pow_of_two(obj->base.size), BUS_DMA_WAITOK); 192 if (ret) 193 goto err_st1; 194 loaded = true; 195 #else 196 sg->offset = 0; 197 sg->length = obj->base.size; 198 199 sg_assign_page(sg, (struct page *)vaddr); 200 sg_dma_address(sg) = dma; 201 sg_dma_len(sg) = obj->base.size; 202 #endif 203 204 dst = vaddr; 205 for (i = 0; i < obj->base.size / PAGE_SIZE; i++) { 206 struct page *page; 207 void *src; 208 209 page = shmem_read_mapping_page(mapping, i); 210 if (IS_ERR(page)) 211 goto err_st; 212 213 src = kmap_atomic(page); 214 memcpy(dst, src, PAGE_SIZE); 215 drm_clflush_virt_range(dst, PAGE_SIZE); 216 kunmap_atomic(src); 217 218 #ifdef __NetBSD__ 219 uvm_obj_unwirepages(mapping, i*PAGE_SIZE, (i + 1)*PAGE_SIZE); 220 #else 221 put_page(page); 222 #endif 223 dst += PAGE_SIZE; 224 } 225 226 intel_gt_chipset_flush(&to_i915(obj->base.dev)->gt); 227 228 __i915_gem_object_set_pages(obj, st, obj->base.size); 229 230 return 0; 231 232 #ifdef __NetBSD__ 233 err_st1: 234 if (loaded) 235 bus_dmamap_unload(dmat, st->sgl->sg_dmamap); 236 sg_free_table(st); 237 #endif 238 err_st: 239 kfree(st); 240 err_pci: 241 #ifdef __NetBSD__ 242 if (vaddr) { 243 bus_dmamem_kunmap(dmat, vaddr, 244 roundup_pow_of_two(obj->base.size)); 245 } 246 obj->mm.u.phys.kva = NULL; 247 if (rsegs) 248 bus_dmamem_free(dmat, &obj->mm.u.phys.seg, rsegs); 249 #else 250 dma_free_coherent(&obj->base.dev->pdev->dev, 251 roundup_pow_of_two(obj->base.size), 252 vaddr, dma); 253 #endif 254 return -ENOMEM; 255 } 256 257 static void 258 i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, 259 struct sg_table *pages) 260 { 261 #ifdef __NetBSD__ 262 bus_dma_tag_t dmat = obj->base.dev->dmat; 263 void *vaddr = obj->mm.u.phys.kva; 264 #else 265 dma_addr_t dma = sg_dma_address(pages->sgl); 266 void *vaddr = sg_page(pages->sgl); 267 #endif 268 269 __i915_gem_object_release_shmem(obj, pages, false); 270 271 if (obj->mm.dirty) { 272 #ifdef __NetBSD__ 273 struct uvm_object *mapping = obj->base.filp; 274 #else 275 struct address_space *mapping = obj->base.filp->f_mapping; 276 #endif 277 void *src = vaddr; 278 int i; 279 280 for (i = 0; i < obj->base.size / PAGE_SIZE; i++) { 281 struct page *page; 282 char *dst; 283 284 page = shmem_read_mapping_page(mapping, i); 285 if (IS_ERR(page)) 286 continue; 287 288 dst = kmap_atomic(page); 289 drm_clflush_virt_range(src, PAGE_SIZE); 290 memcpy(dst, src, PAGE_SIZE); 291 kunmap_atomic(dst); 292 293 set_page_dirty(page); 294 #ifdef __NetBSD__ 295 /* XXX mark_page_accessed */ 296 uvm_obj_unwirepages(mapping, i*PAGE_SIZE, 297 (i + 1)*PAGE_SIZE); 298 #else 299 if (obj->mm.madv == I915_MADV_WILLNEED) 300 mark_page_accessed(page); 301 put_page(page); 302 #endif 303 304 src += PAGE_SIZE; 305 } 306 obj->mm.dirty = false; 307 } 308 309 #ifdef __NetBSD__ 310 bus_dmamap_unload(dmat, pages->sgl->sg_dmamap); 311 #endif 312 313 sg_free_table(pages); 314 kfree(pages); 315 316 #ifdef __NetBSD__ 317 bus_dmamem_kunmap(dmat, obj->mm.u.phys.kva, 318 roundup_pow_of_two(obj->base.size)); 319 obj->mm.u.phys.kva = NULL; 320 bus_dmamem_free(dmat, &obj->mm.u.phys.seg, 1); 321 #else 322 dma_free_coherent(&obj->base.dev->pdev->dev, 323 roundup_pow_of_two(obj->base.size), 324 vaddr, dma); 325 #endif 326 } 327 328 static void phys_release(struct drm_i915_gem_object *obj) 329 { 330 #ifdef __NetBSD__ 331 /* XXX Who acquires the reference? */ 332 uao_detach(obj->base.filp); 333 #else 334 fput(obj->base.filp); 335 #endif 336 } 337 338 static const struct drm_i915_gem_object_ops i915_gem_phys_ops = { 339 .get_pages = i915_gem_object_get_pages_phys, 340 .put_pages = i915_gem_object_put_pages_phys, 341 342 .release = phys_release, 343 }; 344 345 int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) 346 { 347 struct sg_table *pages; 348 int err; 349 350 if (align > obj->base.size) 351 return -EINVAL; 352 353 if (obj->ops == &i915_gem_phys_ops) 354 return 0; 355 356 if (obj->ops != &i915_gem_shmem_ops) 357 return -EINVAL; 358 359 err = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE); 360 if (err) 361 return err; 362 363 mutex_lock_nested(&obj->mm.lock, I915_MM_GET_PAGES); 364 365 if (obj->mm.madv != I915_MADV_WILLNEED) { 366 err = -EFAULT; 367 goto err_unlock; 368 } 369 370 if (obj->mm.quirked) { 371 err = -EFAULT; 372 goto err_unlock; 373 } 374 375 if (obj->mm.mapping) { 376 err = -EBUSY; 377 goto err_unlock; 378 } 379 380 pages = __i915_gem_object_unset_pages(obj); 381 382 obj->ops = &i915_gem_phys_ops; 383 384 err = ____i915_gem_object_get_pages(obj); 385 if (err) 386 goto err_xfer; 387 388 /* Perma-pin (until release) the physical set of pages */ 389 __i915_gem_object_pin_pages(obj); 390 391 if (!IS_ERR_OR_NULL(pages)) { 392 i915_gem_shmem_ops.put_pages(obj, pages); 393 i915_gem_object_release_memory_region(obj); 394 } 395 mutex_unlock(&obj->mm.lock); 396 return 0; 397 398 err_xfer: 399 obj->ops = &i915_gem_shmem_ops; 400 if (!IS_ERR_OR_NULL(pages)) { 401 unsigned int sg_page_sizes = i915_sg_page_sizes(pages->sgl); 402 403 __i915_gem_object_set_pages(obj, pages, sg_page_sizes); 404 } 405 err_unlock: 406 mutex_unlock(&obj->mm.lock); 407 return err; 408 } 409 410 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 411 #include "selftests/i915_gem_phys.c" 412 #endif 413