18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * \file drm_vm.c 38c2ecf20Sopenharmony_ci * Memory mapping for DRM 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * \author Rickard E. (Rik) Faith <faith@valinux.com> 68c2ecf20Sopenharmony_ci * \author Gareth Hughes <gareth@valinux.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 138c2ecf20Sopenharmony_ci * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 148c2ecf20Sopenharmony_ci * All Rights Reserved. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 178c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 188c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 198c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 208c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 218c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next 248c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 258c2ecf20Sopenharmony_ci * Software. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 288c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 298c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 308c2ecf20Sopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 318c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 328c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 338c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/export.h> 378c2ecf20Sopenharmony_ci#include <linux/pci.h> 388c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 398c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 408c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#if defined(__ia64__) 438c2ecf20Sopenharmony_ci#include <linux/efi.h> 448c2ecf20Sopenharmony_ci#include <linux/slab.h> 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci#include <linux/mem_encrypt.h> 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include <drm/drm_agpsupport.h> 508c2ecf20Sopenharmony_ci#include <drm/drm_device.h> 518c2ecf20Sopenharmony_ci#include <drm/drm_drv.h> 528c2ecf20Sopenharmony_ci#include <drm/drm_file.h> 538c2ecf20Sopenharmony_ci#include <drm/drm_framebuffer.h> 548c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include "drm_internal.h" 578c2ecf20Sopenharmony_ci#include "drm_legacy.h" 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct drm_vma_entry { 608c2ecf20Sopenharmony_ci struct list_head head; 618c2ecf20Sopenharmony_ci struct vm_area_struct *vma; 628c2ecf20Sopenharmony_ci pid_t pid; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void drm_vm_open(struct vm_area_struct *vma); 668c2ecf20Sopenharmony_cistatic void drm_vm_close(struct vm_area_struct *vma); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic pgprot_t drm_io_prot(struct drm_local_map *map, 698c2ecf20Sopenharmony_ci struct vm_area_struct *vma) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci pgprot_t tmp = vm_get_page_prot(vma->vm_flags); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* We don't want graphics memory to be mapped encrypted */ 748c2ecf20Sopenharmony_ci tmp = pgprot_decrypted(tmp); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \ 778c2ecf20Sopenharmony_ci defined(__mips__) || defined(__loongarch__) 788c2ecf20Sopenharmony_ci if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING)) 798c2ecf20Sopenharmony_ci tmp = pgprot_noncached(tmp); 808c2ecf20Sopenharmony_ci else 818c2ecf20Sopenharmony_ci tmp = pgprot_writecombine(tmp); 828c2ecf20Sopenharmony_ci#elif defined(__ia64__) 838c2ecf20Sopenharmony_ci if (efi_range_is_wc(vma->vm_start, vma->vm_end - 848c2ecf20Sopenharmony_ci vma->vm_start)) 858c2ecf20Sopenharmony_ci tmp = pgprot_writecombine(tmp); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci tmp = pgprot_noncached(tmp); 888c2ecf20Sopenharmony_ci#elif defined(__sparc__) || defined(__arm__) 898c2ecf20Sopenharmony_ci tmp = pgprot_noncached(tmp); 908c2ecf20Sopenharmony_ci#endif 918c2ecf20Sopenharmony_ci return tmp; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci pgprot_t tmp = vm_get_page_prot(vma->vm_flags); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE) 998c2ecf20Sopenharmony_ci tmp = pgprot_noncached_wc(tmp); 1008c2ecf20Sopenharmony_ci#endif 1018c2ecf20Sopenharmony_ci return tmp; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * \c fault method for AGP virtual memory. 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * \param vma virtual memory area. 1088c2ecf20Sopenharmony_ci * \param address access address. 1098c2ecf20Sopenharmony_ci * \return pointer to the page structure. 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * Find the right map and if it's AGP memory find the real physical page to 1128c2ecf20Sopenharmony_ci * map, get the page, increment the use count and return it. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP) 1158c2ecf20Sopenharmony_cistatic vm_fault_t drm_vm_fault(struct vm_fault *vmf) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 1188c2ecf20Sopenharmony_ci struct drm_file *priv = vma->vm_file->private_data; 1198c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 1208c2ecf20Sopenharmony_ci struct drm_local_map *map = NULL; 1218c2ecf20Sopenharmony_ci struct drm_map_list *r_list; 1228c2ecf20Sopenharmony_ci struct drm_hash_item *hash; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * Find the right map 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci if (!dev->agp) 1288c2ecf20Sopenharmony_ci goto vm_fault_error; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (!dev->agp || !dev->agp->cant_use_aperture) 1318c2ecf20Sopenharmony_ci goto vm_fault_error; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) 1348c2ecf20Sopenharmony_ci goto vm_fault_error; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci r_list = drm_hash_entry(hash, struct drm_map_list, hash); 1378c2ecf20Sopenharmony_ci map = r_list->map; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (map && map->type == _DRM_AGP) { 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * Using vm_pgoff as a selector forces us to use this unusual 1428c2ecf20Sopenharmony_ci * addressing scheme. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci resource_size_t offset = vmf->address - vma->vm_start; 1458c2ecf20Sopenharmony_ci resource_size_t baddr = map->offset + offset; 1468c2ecf20Sopenharmony_ci struct drm_agp_mem *agpmem; 1478c2ecf20Sopenharmony_ci struct page *page; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#ifdef __alpha__ 1508c2ecf20Sopenharmony_ci /* 1518c2ecf20Sopenharmony_ci * Adjust to a bus-relative address 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci baddr -= dev->hose->mem_space->start; 1548c2ecf20Sopenharmony_ci#endif 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* 1578c2ecf20Sopenharmony_ci * It's AGP memory - find the real physical page to map 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci list_for_each_entry(agpmem, &dev->agp->memory, head) { 1608c2ecf20Sopenharmony_ci if (agpmem->bound <= baddr && 1618c2ecf20Sopenharmony_ci agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (&agpmem->head == &dev->agp->memory) 1668c2ecf20Sopenharmony_ci goto vm_fault_error; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * Get the page, inc the use count, and return it 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_ci offset = (baddr - agpmem->bound) >> PAGE_SHIFT; 1728c2ecf20Sopenharmony_ci page = agpmem->memory->pages[offset]; 1738c2ecf20Sopenharmony_ci get_page(page); 1748c2ecf20Sopenharmony_ci vmf->page = page; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci DRM_DEBUG 1778c2ecf20Sopenharmony_ci ("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n", 1788c2ecf20Sopenharmony_ci (unsigned long long)baddr, 1798c2ecf20Sopenharmony_ci agpmem->memory->pages[offset], 1808c2ecf20Sopenharmony_ci (unsigned long long)offset, 1818c2ecf20Sopenharmony_ci page_count(page)); 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_civm_fault_error: 1858c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* Disallow mremap */ 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci#else 1888c2ecf20Sopenharmony_cistatic vm_fault_t drm_vm_fault(struct vm_fault *vmf) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * \c nopage method for shared virtual memory. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * \param vma virtual memory area. 1988c2ecf20Sopenharmony_ci * \param address access address. 1998c2ecf20Sopenharmony_ci * \return pointer to the page structure. 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * Get the mapping, find the real physical page to map, get the page, and 2028c2ecf20Sopenharmony_ci * return it. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_cistatic vm_fault_t drm_vm_shm_fault(struct vm_fault *vmf) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 2078c2ecf20Sopenharmony_ci struct drm_local_map *map = vma->vm_private_data; 2088c2ecf20Sopenharmony_ci unsigned long offset; 2098c2ecf20Sopenharmony_ci unsigned long i; 2108c2ecf20Sopenharmony_ci struct page *page; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!map) 2138c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* Nothing allocated */ 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci offset = vmf->address - vma->vm_start; 2168c2ecf20Sopenharmony_ci i = (unsigned long)map->handle + offset; 2178c2ecf20Sopenharmony_ci page = vmalloc_to_page((void *)i); 2188c2ecf20Sopenharmony_ci if (!page) 2198c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 2208c2ecf20Sopenharmony_ci get_page(page); 2218c2ecf20Sopenharmony_ci vmf->page = page; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci DRM_DEBUG("shm_fault 0x%lx\n", offset); 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/* 2288c2ecf20Sopenharmony_ci * \c close method for shared virtual memory. 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci * \param vma virtual memory area. 2318c2ecf20Sopenharmony_ci * 2328c2ecf20Sopenharmony_ci * Deletes map information if we are the last 2338c2ecf20Sopenharmony_ci * person to close a mapping and it's not in the global maplist. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_cistatic void drm_vm_shm_close(struct vm_area_struct *vma) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct drm_file *priv = vma->vm_file->private_data; 2388c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 2398c2ecf20Sopenharmony_ci struct drm_vma_entry *pt, *temp; 2408c2ecf20Sopenharmony_ci struct drm_local_map *map; 2418c2ecf20Sopenharmony_ci struct drm_map_list *r_list; 2428c2ecf20Sopenharmony_ci int found_maps = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci DRM_DEBUG("0x%08lx,0x%08lx\n", 2458c2ecf20Sopenharmony_ci vma->vm_start, vma->vm_end - vma->vm_start); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci map = vma->vm_private_data; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 2508c2ecf20Sopenharmony_ci list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { 2518c2ecf20Sopenharmony_ci if (pt->vma->vm_private_data == map) 2528c2ecf20Sopenharmony_ci found_maps++; 2538c2ecf20Sopenharmony_ci if (pt->vma == vma) { 2548c2ecf20Sopenharmony_ci list_del(&pt->head); 2558c2ecf20Sopenharmony_ci kfree(pt); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* We were the only map that was found */ 2608c2ecf20Sopenharmony_ci if (found_maps == 1 && map->flags & _DRM_REMOVABLE) { 2618c2ecf20Sopenharmony_ci /* Check to see if we are in the maplist, if we are not, then 2628c2ecf20Sopenharmony_ci * we delete this mappings information. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci found_maps = 0; 2658c2ecf20Sopenharmony_ci list_for_each_entry(r_list, &dev->maplist, head) { 2668c2ecf20Sopenharmony_ci if (r_list->map == map) 2678c2ecf20Sopenharmony_ci found_maps++; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (!found_maps) { 2718c2ecf20Sopenharmony_ci switch (map->type) { 2728c2ecf20Sopenharmony_ci case _DRM_REGISTERS: 2738c2ecf20Sopenharmony_ci case _DRM_FRAME_BUFFER: 2748c2ecf20Sopenharmony_ci arch_phys_wc_del(map->mtrr); 2758c2ecf20Sopenharmony_ci iounmap(map->handle); 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci case _DRM_SHM: 2788c2ecf20Sopenharmony_ci vfree(map->handle); 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci case _DRM_AGP: 2818c2ecf20Sopenharmony_ci case _DRM_SCATTER_GATHER: 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci case _DRM_CONSISTENT: 2848c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, 2858c2ecf20Sopenharmony_ci map->size, 2868c2ecf20Sopenharmony_ci map->handle, 2878c2ecf20Sopenharmony_ci map->offset); 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci kfree(map); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/* 2978c2ecf20Sopenharmony_ci * \c fault method for DMA virtual memory. 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * \param address access address. 3008c2ecf20Sopenharmony_ci * \return pointer to the page structure. 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * Determine the page number from the page offset and get it from drm_device_dma::pagelist. 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_cistatic vm_fault_t drm_vm_dma_fault(struct vm_fault *vmf) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 3078c2ecf20Sopenharmony_ci struct drm_file *priv = vma->vm_file->private_data; 3088c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 3098c2ecf20Sopenharmony_ci struct drm_device_dma *dma = dev->dma; 3108c2ecf20Sopenharmony_ci unsigned long offset; 3118c2ecf20Sopenharmony_ci unsigned long page_nr; 3128c2ecf20Sopenharmony_ci struct page *page; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!dma) 3158c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* Error */ 3168c2ecf20Sopenharmony_ci if (!dma->pagelist) 3178c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* Nothing allocated */ 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci offset = vmf->address - vma->vm_start; 3208c2ecf20Sopenharmony_ci /* vm_[pg]off[set] should be 0 */ 3218c2ecf20Sopenharmony_ci page_nr = offset >> PAGE_SHIFT; /* page_nr could just be vmf->pgoff */ 3228c2ecf20Sopenharmony_ci page = virt_to_page((void *)dma->pagelist[page_nr]); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci get_page(page); 3258c2ecf20Sopenharmony_ci vmf->page = page; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci DRM_DEBUG("dma_fault 0x%lx (page %lu)\n", offset, page_nr); 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* 3328c2ecf20Sopenharmony_ci * \c fault method for scatter-gather virtual memory. 3338c2ecf20Sopenharmony_ci * 3348c2ecf20Sopenharmony_ci * \param address access address. 3358c2ecf20Sopenharmony_ci * \return pointer to the page structure. 3368c2ecf20Sopenharmony_ci * 3378c2ecf20Sopenharmony_ci * Determine the map offset from the page offset and get it from drm_sg_mem::pagelist. 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_cistatic vm_fault_t drm_vm_sg_fault(struct vm_fault *vmf) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 3428c2ecf20Sopenharmony_ci struct drm_local_map *map = vma->vm_private_data; 3438c2ecf20Sopenharmony_ci struct drm_file *priv = vma->vm_file->private_data; 3448c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 3458c2ecf20Sopenharmony_ci struct drm_sg_mem *entry = dev->sg; 3468c2ecf20Sopenharmony_ci unsigned long offset; 3478c2ecf20Sopenharmony_ci unsigned long map_offset; 3488c2ecf20Sopenharmony_ci unsigned long page_offset; 3498c2ecf20Sopenharmony_ci struct page *page; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (!entry) 3528c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* Error */ 3538c2ecf20Sopenharmony_ci if (!entry->pagelist) 3548c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; /* Nothing allocated */ 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci offset = vmf->address - vma->vm_start; 3578c2ecf20Sopenharmony_ci map_offset = map->offset - (unsigned long)dev->sg->virtual; 3588c2ecf20Sopenharmony_ci page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT); 3598c2ecf20Sopenharmony_ci page = entry->pagelist[page_offset]; 3608c2ecf20Sopenharmony_ci get_page(page); 3618c2ecf20Sopenharmony_ci vmf->page = page; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/** AGP virtual memory operations */ 3678c2ecf20Sopenharmony_cistatic const struct vm_operations_struct drm_vm_ops = { 3688c2ecf20Sopenharmony_ci .fault = drm_vm_fault, 3698c2ecf20Sopenharmony_ci .open = drm_vm_open, 3708c2ecf20Sopenharmony_ci .close = drm_vm_close, 3718c2ecf20Sopenharmony_ci}; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci/** Shared virtual memory operations */ 3748c2ecf20Sopenharmony_cistatic const struct vm_operations_struct drm_vm_shm_ops = { 3758c2ecf20Sopenharmony_ci .fault = drm_vm_shm_fault, 3768c2ecf20Sopenharmony_ci .open = drm_vm_open, 3778c2ecf20Sopenharmony_ci .close = drm_vm_shm_close, 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/** DMA virtual memory operations */ 3818c2ecf20Sopenharmony_cistatic const struct vm_operations_struct drm_vm_dma_ops = { 3828c2ecf20Sopenharmony_ci .fault = drm_vm_dma_fault, 3838c2ecf20Sopenharmony_ci .open = drm_vm_open, 3848c2ecf20Sopenharmony_ci .close = drm_vm_close, 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/** Scatter-gather virtual memory operations */ 3888c2ecf20Sopenharmony_cistatic const struct vm_operations_struct drm_vm_sg_ops = { 3898c2ecf20Sopenharmony_ci .fault = drm_vm_sg_fault, 3908c2ecf20Sopenharmony_ci .open = drm_vm_open, 3918c2ecf20Sopenharmony_ci .close = drm_vm_close, 3928c2ecf20Sopenharmony_ci}; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic void drm_vm_open_locked(struct drm_device *dev, 3958c2ecf20Sopenharmony_ci struct vm_area_struct *vma) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci struct drm_vma_entry *vma_entry; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci DRM_DEBUG("0x%08lx,0x%08lx\n", 4008c2ecf20Sopenharmony_ci vma->vm_start, vma->vm_end - vma->vm_start); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci vma_entry = kmalloc(sizeof(*vma_entry), GFP_KERNEL); 4038c2ecf20Sopenharmony_ci if (vma_entry) { 4048c2ecf20Sopenharmony_ci vma_entry->vma = vma; 4058c2ecf20Sopenharmony_ci vma_entry->pid = current->pid; 4068c2ecf20Sopenharmony_ci list_add(&vma_entry->head, &dev->vmalist); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic void drm_vm_open(struct vm_area_struct *vma) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct drm_file *priv = vma->vm_file->private_data; 4138c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 4168c2ecf20Sopenharmony_ci drm_vm_open_locked(dev, vma); 4178c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void drm_vm_close_locked(struct drm_device *dev, 4218c2ecf20Sopenharmony_ci struct vm_area_struct *vma) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct drm_vma_entry *pt, *temp; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci DRM_DEBUG("0x%08lx,0x%08lx\n", 4268c2ecf20Sopenharmony_ci vma->vm_start, vma->vm_end - vma->vm_start); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { 4298c2ecf20Sopenharmony_ci if (pt->vma == vma) { 4308c2ecf20Sopenharmony_ci list_del(&pt->head); 4318c2ecf20Sopenharmony_ci kfree(pt); 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci/* 4388c2ecf20Sopenharmony_ci * \c close method for all virtual memory types. 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * \param vma virtual memory area. 4418c2ecf20Sopenharmony_ci * 4428c2ecf20Sopenharmony_ci * Search the \p vma private data entry in drm_device::vmalist, unlink it, and 4438c2ecf20Sopenharmony_ci * free it. 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_cistatic void drm_vm_close(struct vm_area_struct *vma) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct drm_file *priv = vma->vm_file->private_data; 4488c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 4518c2ecf20Sopenharmony_ci drm_vm_close_locked(dev, vma); 4528c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/* 4568c2ecf20Sopenharmony_ci * mmap DMA memory. 4578c2ecf20Sopenharmony_ci * 4588c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 4598c2ecf20Sopenharmony_ci * \param vma virtual memory area. 4608c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * Sets the virtual memory area operations structure to vm_dma_ops, the file 4638c2ecf20Sopenharmony_ci * pointer, and calls vm_open(). 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_cistatic int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct drm_file *priv = filp->private_data; 4688c2ecf20Sopenharmony_ci struct drm_device *dev; 4698c2ecf20Sopenharmony_ci struct drm_device_dma *dma; 4708c2ecf20Sopenharmony_ci unsigned long length = vma->vm_end - vma->vm_start; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci dev = priv->minor->dev; 4738c2ecf20Sopenharmony_ci dma = dev->dma; 4748c2ecf20Sopenharmony_ci DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", 4758c2ecf20Sopenharmony_ci vma->vm_start, vma->vm_end, vma->vm_pgoff); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Length must match exact page count */ 4788c2ecf20Sopenharmony_ci if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { 4798c2ecf20Sopenharmony_ci return -EINVAL; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN) && 4838c2ecf20Sopenharmony_ci (dma->flags & _DRM_DMA_USE_PCI_RO)) { 4848c2ecf20Sopenharmony_ci vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); 4858c2ecf20Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 4868c2ecf20Sopenharmony_ci pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; 4878c2ecf20Sopenharmony_ci#else 4888c2ecf20Sopenharmony_ci /* Ye gads this is ugly. With more thought 4898c2ecf20Sopenharmony_ci we could move this up higher and use 4908c2ecf20Sopenharmony_ci `protection_map' instead. */ 4918c2ecf20Sopenharmony_ci vma->vm_page_prot = 4928c2ecf20Sopenharmony_ci __pgprot(pte_val 4938c2ecf20Sopenharmony_ci (pte_wrprotect 4948c2ecf20Sopenharmony_ci (__pte(pgprot_val(vma->vm_page_prot))))); 4958c2ecf20Sopenharmony_ci#endif 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci vma->vm_ops = &drm_vm_dma_ops; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci drm_vm_open_locked(dev, vma); 5038c2ecf20Sopenharmony_ci return 0; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic resource_size_t drm_core_get_reg_ofs(struct drm_device *dev) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci#ifdef __alpha__ 5098c2ecf20Sopenharmony_ci return dev->hose->dense_mem_base; 5108c2ecf20Sopenharmony_ci#else 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci#endif 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* 5168c2ecf20Sopenharmony_ci * mmap DMA memory. 5178c2ecf20Sopenharmony_ci * 5188c2ecf20Sopenharmony_ci * \param file_priv DRM file private. 5198c2ecf20Sopenharmony_ci * \param vma virtual memory area. 5208c2ecf20Sopenharmony_ci * \return zero on success or a negative number on failure. 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * If the virtual memory area has no offset associated with it then it's a DMA 5238c2ecf20Sopenharmony_ci * area, so calls mmap_dma(). Otherwise searches the map in drm_device::maplist, 5248c2ecf20Sopenharmony_ci * checks that the restricted flag is not set, sets the virtual memory operations 5258c2ecf20Sopenharmony_ci * according to the mapping type and remaps the pages. Finally sets the file 5268c2ecf20Sopenharmony_ci * pointer and calls vm_open(). 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_cistatic int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct drm_file *priv = filp->private_data; 5318c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 5328c2ecf20Sopenharmony_ci struct drm_local_map *map = NULL; 5338c2ecf20Sopenharmony_ci resource_size_t offset = 0; 5348c2ecf20Sopenharmony_ci struct drm_hash_item *hash; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", 5378c2ecf20Sopenharmony_ci vma->vm_start, vma->vm_end, vma->vm_pgoff); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (!priv->authenticated) 5408c2ecf20Sopenharmony_ci return -EACCES; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* We check for "dma". On Apple's UniNorth, it's valid to have 5438c2ecf20Sopenharmony_ci * the AGP mapped at physical address 0 5448c2ecf20Sopenharmony_ci * --BenH. 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_ci if (!vma->vm_pgoff 5478c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP) 5488c2ecf20Sopenharmony_ci && (!dev->agp 5498c2ecf20Sopenharmony_ci || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) 5508c2ecf20Sopenharmony_ci#endif 5518c2ecf20Sopenharmony_ci ) 5528c2ecf20Sopenharmony_ci return drm_mmap_dma(filp, vma); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) { 5558c2ecf20Sopenharmony_ci DRM_ERROR("Could not find map\n"); 5568c2ecf20Sopenharmony_ci return -EINVAL; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci map = drm_hash_entry(hash, struct drm_map_list, hash)->map; 5608c2ecf20Sopenharmony_ci if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) 5618c2ecf20Sopenharmony_ci return -EPERM; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* Check for valid size. */ 5648c2ecf20Sopenharmony_ci if (map->size < vma->vm_end - vma->vm_start) 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { 5688c2ecf20Sopenharmony_ci vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); 5698c2ecf20Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 5708c2ecf20Sopenharmony_ci pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; 5718c2ecf20Sopenharmony_ci#else 5728c2ecf20Sopenharmony_ci /* Ye gads this is ugly. With more thought 5738c2ecf20Sopenharmony_ci we could move this up higher and use 5748c2ecf20Sopenharmony_ci `protection_map' instead. */ 5758c2ecf20Sopenharmony_ci vma->vm_page_prot = 5768c2ecf20Sopenharmony_ci __pgprot(pte_val 5778c2ecf20Sopenharmony_ci (pte_wrprotect 5788c2ecf20Sopenharmony_ci (__pte(pgprot_val(vma->vm_page_prot))))); 5798c2ecf20Sopenharmony_ci#endif 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci switch (map->type) { 5838c2ecf20Sopenharmony_ci#if !defined(__arm__) 5848c2ecf20Sopenharmony_ci case _DRM_AGP: 5858c2ecf20Sopenharmony_ci if (dev->agp && dev->agp->cant_use_aperture) { 5868c2ecf20Sopenharmony_ci /* 5878c2ecf20Sopenharmony_ci * On some platforms we can't talk to bus dma address from the CPU, so for 5888c2ecf20Sopenharmony_ci * memory of type DRM_AGP, we'll deal with sorting out the real physical 5898c2ecf20Sopenharmony_ci * pages and mappings in fault() 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci#if defined(__powerpc__) 5928c2ecf20Sopenharmony_ci vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 5938c2ecf20Sopenharmony_ci#endif 5948c2ecf20Sopenharmony_ci vma->vm_ops = &drm_vm_ops; 5958c2ecf20Sopenharmony_ci break; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci fallthrough; /* to _DRM_FRAME_BUFFER... */ 5988c2ecf20Sopenharmony_ci#endif 5998c2ecf20Sopenharmony_ci case _DRM_FRAME_BUFFER: 6008c2ecf20Sopenharmony_ci case _DRM_REGISTERS: 6018c2ecf20Sopenharmony_ci offset = drm_core_get_reg_ofs(dev); 6028c2ecf20Sopenharmony_ci vma->vm_page_prot = drm_io_prot(map, vma); 6038c2ecf20Sopenharmony_ci if (io_remap_pfn_range(vma, vma->vm_start, 6048c2ecf20Sopenharmony_ci (map->offset + offset) >> PAGE_SHIFT, 6058c2ecf20Sopenharmony_ci vma->vm_end - vma->vm_start, 6068c2ecf20Sopenharmony_ci vma->vm_page_prot)) 6078c2ecf20Sopenharmony_ci return -EAGAIN; 6088c2ecf20Sopenharmony_ci DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," 6098c2ecf20Sopenharmony_ci " offset = 0x%llx\n", 6108c2ecf20Sopenharmony_ci map->type, 6118c2ecf20Sopenharmony_ci vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset)); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci vma->vm_ops = &drm_vm_ops; 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci case _DRM_CONSISTENT: 6168c2ecf20Sopenharmony_ci /* Consistent memory is really like shared memory. But 6178c2ecf20Sopenharmony_ci * it's allocated in a different way, so avoid fault */ 6188c2ecf20Sopenharmony_ci if (remap_pfn_range(vma, vma->vm_start, 6198c2ecf20Sopenharmony_ci page_to_pfn(virt_to_page(map->handle)), 6208c2ecf20Sopenharmony_ci vma->vm_end - vma->vm_start, vma->vm_page_prot)) 6218c2ecf20Sopenharmony_ci return -EAGAIN; 6228c2ecf20Sopenharmony_ci vma->vm_page_prot = drm_dma_prot(map->type, vma); 6238c2ecf20Sopenharmony_ci fallthrough; /* to _DRM_SHM */ 6248c2ecf20Sopenharmony_ci case _DRM_SHM: 6258c2ecf20Sopenharmony_ci vma->vm_ops = &drm_vm_shm_ops; 6268c2ecf20Sopenharmony_ci vma->vm_private_data = (void *)map; 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci case _DRM_SCATTER_GATHER: 6298c2ecf20Sopenharmony_ci vma->vm_ops = &drm_vm_sg_ops; 6308c2ecf20Sopenharmony_ci vma->vm_private_data = (void *)map; 6318c2ecf20Sopenharmony_ci vma->vm_page_prot = drm_dma_prot(map->type, vma); 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci default: 6348c2ecf20Sopenharmony_ci return -EINVAL; /* This should never happen. */ 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci drm_vm_open_locked(dev, vma); 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ciint drm_legacy_mmap(struct file *filp, struct vm_area_struct *vma) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct drm_file *priv = filp->private_data; 6458c2ecf20Sopenharmony_ci struct drm_device *dev = priv->minor->dev; 6468c2ecf20Sopenharmony_ci int ret; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (drm_dev_is_unplugged(dev)) 6498c2ecf20Sopenharmony_ci return -ENODEV; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci mutex_lock(&dev->struct_mutex); 6528c2ecf20Sopenharmony_ci ret = drm_mmap_locked(filp, vma); 6538c2ecf20Sopenharmony_ci mutex_unlock(&dev->struct_mutex); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return ret; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_legacy_mmap); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_LEGACY) 6608c2ecf20Sopenharmony_civoid drm_legacy_vma_flush(struct drm_device *dev) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct drm_vma_entry *vma, *vma_temp; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* Clear vma list (only needed for legacy drivers) */ 6658c2ecf20Sopenharmony_ci list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { 6668c2ecf20Sopenharmony_ci list_del(&vma->head); 6678c2ecf20Sopenharmony_ci kfree(vma); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci#endif 671