LCOV - code coverage report
Current view: top level - drivers/gpu/drm/ttm - ttm_bo_vm.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 147 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: GPL-2.0 OR MIT */
       2             : /**************************************************************************
       3             :  *
       4             :  * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
       5             :  * All Rights Reserved.
       6             :  *
       7             :  * Permission is hereby granted, free of charge, to any person obtaining a
       8             :  * copy of this software and associated documentation files (the
       9             :  * "Software"), to deal in the Software without restriction, including
      10             :  * without limitation the rights to use, copy, modify, merge, publish,
      11             :  * distribute, sub license, and/or sell copies of the Software, and to
      12             :  * permit persons to whom the Software is furnished to do so, subject to
      13             :  * the following conditions:
      14             :  *
      15             :  * The above copyright notice and this permission notice (including the
      16             :  * next paragraph) shall be included in all copies or substantial portions
      17             :  * of the Software.
      18             :  *
      19             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             :  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
      22             :  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
      23             :  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
      24             :  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
      25             :  * USE OR OTHER DEALINGS IN THE SOFTWARE.
      26             :  *
      27             :  **************************************************************************/
      28             : /*
      29             :  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
      30             :  */
      31             : 
      32             : #define pr_fmt(fmt) "[TTM] " fmt
      33             : 
      34             : #include <drm/ttm/ttm_bo_driver.h>
      35             : #include <drm/ttm/ttm_placement.h>
      36             : #include <drm/drm_vma_manager.h>
      37             : #include <drm/drm_drv.h>
      38             : #include <drm/drm_managed.h>
      39             : #include <linux/mm.h>
      40             : #include <linux/pfn_t.h>
      41             : #include <linux/rbtree.h>
      42             : #include <linux/module.h>
      43             : #include <linux/uaccess.h>
      44             : #include <linux/mem_encrypt.h>
      45             : 
      46           0 : static vm_fault_t ttm_bo_vm_fault_idle(struct ttm_buffer_object *bo,
      47             :                                 struct vm_fault *vmf)
      48             : {
      49           0 :         long err = 0;
      50             : 
      51             :         /*
      52             :          * Quick non-stalling check for idle.
      53             :          */
      54           0 :         if (dma_resv_test_signaled(bo->base.resv, DMA_RESV_USAGE_KERNEL))
      55             :                 return 0;
      56             : 
      57             :         /*
      58             :          * If possible, avoid waiting for GPU with mmap_lock
      59             :          * held.  We only do this if the fault allows retry and this
      60             :          * is the first attempt.
      61             :          */
      62           0 :         if (fault_flag_allow_retry_first(vmf->flags)) {
      63           0 :                 if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT)
      64             :                         return VM_FAULT_RETRY;
      65             : 
      66           0 :                 ttm_bo_get(bo);
      67           0 :                 mmap_read_unlock(vmf->vma->vm_mm);
      68           0 :                 (void)dma_resv_wait_timeout(bo->base.resv,
      69             :                                             DMA_RESV_USAGE_KERNEL, true,
      70             :                                             MAX_SCHEDULE_TIMEOUT);
      71           0 :                 dma_resv_unlock(bo->base.resv);
      72           0 :                 ttm_bo_put(bo);
      73             :                 return VM_FAULT_RETRY;
      74             :         }
      75             : 
      76             :         /*
      77             :          * Ordinary wait.
      78             :          */
      79           0 :         err = dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_KERNEL, true,
      80             :                                     MAX_SCHEDULE_TIMEOUT);
      81           0 :         if (unlikely(err < 0)) {
      82           0 :                 return (err != -ERESTARTSYS) ? VM_FAULT_SIGBUS :
      83             :                         VM_FAULT_NOPAGE;
      84             :         }
      85             : 
      86             :         return 0;
      87             : }
      88             : 
      89             : static unsigned long ttm_bo_io_mem_pfn(struct ttm_buffer_object *bo,
      90             :                                        unsigned long page_offset)
      91             : {
      92           0 :         struct ttm_device *bdev = bo->bdev;
      93             : 
      94           0 :         if (bdev->funcs->io_mem_pfn)
      95           0 :                 return bdev->funcs->io_mem_pfn(bo, page_offset);
      96             : 
      97           0 :         return (bo->resource->bus.offset >> PAGE_SHIFT) + page_offset;
      98             : }
      99             : 
     100             : /**
     101             :  * ttm_bo_vm_reserve - Reserve a buffer object in a retryable vm callback
     102             :  * @bo: The buffer object
     103             :  * @vmf: The fault structure handed to the callback
     104             :  *
     105             :  * vm callbacks like fault() and *_mkwrite() allow for the mm_sem to be dropped
     106             :  * during long waits, and after the wait the callback will be restarted. This
     107             :  * is to allow other threads using the same virtual memory space concurrent
     108             :  * access to map(), unmap() completely unrelated buffer objects. TTM buffer
     109             :  * object reservations sometimes wait for GPU and should therefore be
     110             :  * considered long waits. This function reserves the buffer object interruptibly
     111             :  * taking this into account. Starvation is avoided by the vm system not
     112             :  * allowing too many repeated restarts.
     113             :  * This function is intended to be used in customized fault() and _mkwrite()
     114             :  * handlers.
     115             :  *
     116             :  * Return:
     117             :  *    0 on success and the bo was reserved.
     118             :  *    VM_FAULT_RETRY if blocking wait.
     119             :  *    VM_FAULT_NOPAGE if blocking wait and retrying was not allowed.
     120             :  */
     121           0 : vm_fault_t ttm_bo_vm_reserve(struct ttm_buffer_object *bo,
     122             :                              struct vm_fault *vmf)
     123             : {
     124             :         /*
     125             :          * Work around locking order reversal in fault / nopfn
     126             :          * between mmap_lock and bo_reserve: Perform a trylock operation
     127             :          * for reserve, and if it fails, retry the fault after waiting
     128             :          * for the buffer to become unreserved.
     129             :          */
     130           0 :         if (unlikely(!dma_resv_trylock(bo->base.resv))) {
     131             :                 /*
     132             :                  * If the fault allows retry and this is the first
     133             :                  * fault attempt, we try to release the mmap_lock
     134             :                  * before waiting
     135             :                  */
     136           0 :                 if (fault_flag_allow_retry_first(vmf->flags)) {
     137           0 :                         if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) {
     138           0 :                                 ttm_bo_get(bo);
     139           0 :                                 mmap_read_unlock(vmf->vma->vm_mm);
     140           0 :                                 if (!dma_resv_lock_interruptible(bo->base.resv,
     141             :                                                                  NULL))
     142           0 :                                         dma_resv_unlock(bo->base.resv);
     143           0 :                                 ttm_bo_put(bo);
     144             :                         }
     145             : 
     146             :                         return VM_FAULT_RETRY;
     147             :                 }
     148             : 
     149           0 :                 if (dma_resv_lock_interruptible(bo->base.resv, NULL))
     150             :                         return VM_FAULT_NOPAGE;
     151             :         }
     152             : 
     153             :         /*
     154             :          * Refuse to fault imported pages. This should be handled
     155             :          * (if at all) by redirecting mmap to the exporter.
     156             :          */
     157           0 :         if (bo->ttm && (bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL)) {
     158           0 :                 if (!(bo->ttm->page_flags & TTM_TT_FLAG_EXTERNAL_MAPPABLE)) {
     159           0 :                         dma_resv_unlock(bo->base.resv);
     160           0 :                         return VM_FAULT_SIGBUS;
     161             :                 }
     162             :         }
     163             : 
     164             :         return 0;
     165             : }
     166             : EXPORT_SYMBOL(ttm_bo_vm_reserve);
     167             : 
     168             : /**
     169             :  * ttm_bo_vm_fault_reserved - TTM fault helper
     170             :  * @vmf: The struct vm_fault given as argument to the fault callback
     171             :  * @prot: The page protection to be used for this memory area.
     172             :  * @num_prefault: Maximum number of prefault pages. The caller may want to
     173             :  * specify this based on madvice settings and the size of the GPU object
     174             :  * backed by the memory.
     175             :  *
     176             :  * This function inserts one or more page table entries pointing to the
     177             :  * memory backing the buffer object, and then returns a return code
     178             :  * instructing the caller to retry the page access.
     179             :  *
     180             :  * Return:
     181             :  *   VM_FAULT_NOPAGE on success or pending signal
     182             :  *   VM_FAULT_SIGBUS on unspecified error
     183             :  *   VM_FAULT_OOM on out-of-memory
     184             :  *   VM_FAULT_RETRY if retryable wait
     185             :  */
     186           0 : vm_fault_t ttm_bo_vm_fault_reserved(struct vm_fault *vmf,
     187             :                                     pgprot_t prot,
     188             :                                     pgoff_t num_prefault)
     189             : {
     190           0 :         struct vm_area_struct *vma = vmf->vma;
     191           0 :         struct ttm_buffer_object *bo = vma->vm_private_data;
     192           0 :         struct ttm_device *bdev = bo->bdev;
     193             :         unsigned long page_offset;
     194             :         unsigned long page_last;
     195             :         unsigned long pfn;
     196           0 :         struct ttm_tt *ttm = NULL;
     197             :         struct page *page;
     198             :         int err;
     199             :         pgoff_t i;
     200           0 :         vm_fault_t ret = VM_FAULT_NOPAGE;
     201           0 :         unsigned long address = vmf->address;
     202             : 
     203             :         /*
     204             :          * Wait for buffer data in transit, due to a pipelined
     205             :          * move.
     206             :          */
     207           0 :         ret = ttm_bo_vm_fault_idle(bo, vmf);
     208           0 :         if (unlikely(ret != 0))
     209             :                 return ret;
     210             : 
     211           0 :         err = ttm_mem_io_reserve(bdev, bo->resource);
     212           0 :         if (unlikely(err != 0))
     213             :                 return VM_FAULT_SIGBUS;
     214             : 
     215           0 :         page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) +
     216           0 :                 vma->vm_pgoff - drm_vma_node_start(&bo->base.vma_node);
     217           0 :         page_last = vma_pages(vma) + vma->vm_pgoff -
     218           0 :                 drm_vma_node_start(&bo->base.vma_node);
     219             : 
     220           0 :         if (unlikely(page_offset >= bo->resource->num_pages))
     221             :                 return VM_FAULT_SIGBUS;
     222             : 
     223           0 :         prot = ttm_io_prot(bo, bo->resource, prot);
     224           0 :         if (!bo->resource->bus.is_iomem) {
     225           0 :                 struct ttm_operation_ctx ctx = {
     226             :                         .interruptible = false,
     227             :                         .no_wait_gpu = false,
     228             :                         .force_alloc = true
     229             :                 };
     230             : 
     231           0 :                 ttm = bo->ttm;
     232           0 :                 if (ttm_tt_populate(bdev, bo->ttm, &ctx))
     233           0 :                         return VM_FAULT_OOM;
     234             :         } else {
     235             :                 /* Iomem should not be marked encrypted */
     236             :                 prot = pgprot_decrypted(prot);
     237             :         }
     238             : 
     239             :         /*
     240             :          * Speculatively prefault a number of pages. Only error on
     241             :          * first page.
     242             :          */
     243           0 :         for (i = 0; i < num_prefault; ++i) {
     244           0 :                 if (bo->resource->bus.is_iomem) {
     245             :                         pfn = ttm_bo_io_mem_pfn(bo, page_offset);
     246             :                 } else {
     247           0 :                         page = ttm->pages[page_offset];
     248           0 :                         if (unlikely(!page && i == 0)) {
     249             :                                 return VM_FAULT_OOM;
     250           0 :                         } else if (unlikely(!page)) {
     251             :                                 break;
     252             :                         }
     253           0 :                         pfn = page_to_pfn(page);
     254             :                 }
     255             : 
     256             :                 /*
     257             :                  * Note that the value of @prot at this point may differ from
     258             :                  * the value of @vma->vm_page_prot in the caching- and
     259             :                  * encryption bits. This is because the exact location of the
     260             :                  * data may not be known at mmap() time and may also change
     261             :                  * at arbitrary times while the data is mmap'ed.
     262             :                  * See vmf_insert_mixed_prot() for a discussion.
     263             :                  */
     264           0 :                 ret = vmf_insert_pfn_prot(vma, address, pfn, prot);
     265             : 
     266             :                 /* Never error on prefaulted PTEs */
     267           0 :                 if (unlikely((ret & VM_FAULT_ERROR))) {
     268           0 :                         if (i == 0)
     269             :                                 return VM_FAULT_NOPAGE;
     270             :                         else
     271             :                                 break;
     272             :                 }
     273             : 
     274           0 :                 address += PAGE_SIZE;
     275           0 :                 if (unlikely(++page_offset >= page_last))
     276             :                         break;
     277             :         }
     278             :         return ret;
     279             : }
     280             : EXPORT_SYMBOL(ttm_bo_vm_fault_reserved);
     281             : 
     282           0 : static void ttm_bo_release_dummy_page(struct drm_device *dev, void *res)
     283             : {
     284           0 :         struct page *dummy_page = (struct page *)res;
     285             : 
     286           0 :         __free_page(dummy_page);
     287           0 : }
     288             : 
     289           0 : vm_fault_t ttm_bo_vm_dummy_page(struct vm_fault *vmf, pgprot_t prot)
     290             : {
     291           0 :         struct vm_area_struct *vma = vmf->vma;
     292           0 :         struct ttm_buffer_object *bo = vma->vm_private_data;
     293           0 :         struct drm_device *ddev = bo->base.dev;
     294           0 :         vm_fault_t ret = VM_FAULT_NOPAGE;
     295             :         unsigned long address;
     296             :         unsigned long pfn;
     297             :         struct page *page;
     298             : 
     299             :         /* Allocate new dummy page to map all the VA range in this VMA to it*/
     300           0 :         page = alloc_page(GFP_KERNEL | __GFP_ZERO);
     301           0 :         if (!page)
     302             :                 return VM_FAULT_OOM;
     303             : 
     304             :         /* Set the page to be freed using drmm release action */
     305           0 :         if (drmm_add_action_or_reset(ddev, ttm_bo_release_dummy_page, page))
     306             :                 return VM_FAULT_OOM;
     307             : 
     308           0 :         pfn = page_to_pfn(page);
     309             : 
     310             :         /* Prefault the entire VMA range right away to avoid further faults */
     311           0 :         for (address = vma->vm_start; address < vma->vm_end;
     312           0 :              address += PAGE_SIZE)
     313           0 :                 ret = vmf_insert_pfn_prot(vma, address, pfn, prot);
     314             : 
     315             :         return ret;
     316             : }
     317             : EXPORT_SYMBOL(ttm_bo_vm_dummy_page);
     318             : 
     319           0 : vm_fault_t ttm_bo_vm_fault(struct vm_fault *vmf)
     320             : {
     321           0 :         struct vm_area_struct *vma = vmf->vma;
     322             :         pgprot_t prot;
     323           0 :         struct ttm_buffer_object *bo = vma->vm_private_data;
     324           0 :         struct drm_device *ddev = bo->base.dev;
     325             :         vm_fault_t ret;
     326             :         int idx;
     327             : 
     328           0 :         ret = ttm_bo_vm_reserve(bo, vmf);
     329           0 :         if (ret)
     330             :                 return ret;
     331             : 
     332           0 :         prot = vma->vm_page_prot;
     333           0 :         if (drm_dev_enter(ddev, &idx)) {
     334           0 :                 ret = ttm_bo_vm_fault_reserved(vmf, prot, TTM_BO_VM_NUM_PREFAULT);
     335           0 :                 drm_dev_exit(idx);
     336             :         } else {
     337           0 :                 ret = ttm_bo_vm_dummy_page(vmf, prot);
     338             :         }
     339           0 :         if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
     340             :                 return ret;
     341             : 
     342           0 :         dma_resv_unlock(bo->base.resv);
     343             : 
     344           0 :         return ret;
     345             : }
     346             : EXPORT_SYMBOL(ttm_bo_vm_fault);
     347             : 
     348           0 : void ttm_bo_vm_open(struct vm_area_struct *vma)
     349             : {
     350           0 :         struct ttm_buffer_object *bo = vma->vm_private_data;
     351             : 
     352           0 :         WARN_ON(bo->bdev->dev_mapping != vma->vm_file->f_mapping);
     353             : 
     354           0 :         ttm_bo_get(bo);
     355           0 : }
     356             : EXPORT_SYMBOL(ttm_bo_vm_open);
     357             : 
     358           0 : void ttm_bo_vm_close(struct vm_area_struct *vma)
     359             : {
     360           0 :         struct ttm_buffer_object *bo = vma->vm_private_data;
     361             : 
     362           0 :         ttm_bo_put(bo);
     363           0 :         vma->vm_private_data = NULL;
     364           0 : }
     365             : EXPORT_SYMBOL(ttm_bo_vm_close);
     366             : 
     367           0 : static int ttm_bo_vm_access_kmap(struct ttm_buffer_object *bo,
     368             :                                  unsigned long offset,
     369             :                                  uint8_t *buf, int len, int write)
     370             : {
     371           0 :         unsigned long page = offset >> PAGE_SHIFT;
     372           0 :         unsigned long bytes_left = len;
     373             :         int ret;
     374             : 
     375             :         /* Copy a page at a time, that way no extra virtual address
     376             :          * mapping is needed
     377             :          */
     378           0 :         offset -= page << PAGE_SHIFT;
     379             :         do {
     380           0 :                 unsigned long bytes = min(bytes_left, PAGE_SIZE - offset);
     381             :                 struct ttm_bo_kmap_obj map;
     382             :                 void *ptr;
     383             :                 bool is_iomem;
     384             : 
     385           0 :                 ret = ttm_bo_kmap(bo, page, 1, &map);
     386           0 :                 if (ret)
     387           0 :                         return ret;
     388             : 
     389           0 :                 ptr = (uint8_t *)ttm_kmap_obj_virtual(&map, &is_iomem) + offset;
     390           0 :                 WARN_ON_ONCE(is_iomem);
     391           0 :                 if (write)
     392           0 :                         memcpy(ptr, buf, bytes);
     393             :                 else
     394           0 :                         memcpy(buf, ptr, bytes);
     395           0 :                 ttm_bo_kunmap(&map);
     396             : 
     397           0 :                 page++;
     398           0 :                 buf += bytes;
     399           0 :                 bytes_left -= bytes;
     400           0 :                 offset = 0;
     401           0 :         } while (bytes_left);
     402             : 
     403             :         return len;
     404             : }
     405             : 
     406           0 : int ttm_bo_vm_access(struct vm_area_struct *vma, unsigned long addr,
     407             :                      void *buf, int len, int write)
     408             : {
     409           0 :         struct ttm_buffer_object *bo = vma->vm_private_data;
     410           0 :         unsigned long offset = (addr) - vma->vm_start +
     411           0 :                 ((vma->vm_pgoff - drm_vma_node_start(&bo->base.vma_node))
     412           0 :                  << PAGE_SHIFT);
     413             :         int ret;
     414             : 
     415           0 :         if (len < 1 || (offset + len) >> PAGE_SHIFT > bo->resource->num_pages)
     416             :                 return -EIO;
     417             : 
     418           0 :         ret = ttm_bo_reserve(bo, true, false, NULL);
     419           0 :         if (ret)
     420             :                 return ret;
     421             : 
     422           0 :         switch (bo->resource->mem_type) {
     423             :         case TTM_PL_SYSTEM:
     424             :                 fallthrough;
     425             :         case TTM_PL_TT:
     426           0 :                 ret = ttm_bo_vm_access_kmap(bo, offset, buf, len, write);
     427           0 :                 break;
     428             :         default:
     429           0 :                 if (bo->bdev->funcs->access_memory)
     430           0 :                         ret = bo->bdev->funcs->access_memory(
     431             :                                 bo, offset, buf, len, write);
     432             :                 else
     433             :                         ret = -EIO;
     434             :         }
     435             : 
     436           0 :         ttm_bo_unreserve(bo);
     437             : 
     438           0 :         return ret;
     439             : }
     440             : EXPORT_SYMBOL(ttm_bo_vm_access);
     441             : 
     442             : static const struct vm_operations_struct ttm_bo_vm_ops = {
     443             :         .fault = ttm_bo_vm_fault,
     444             :         .open = ttm_bo_vm_open,
     445             :         .close = ttm_bo_vm_close,
     446             :         .access = ttm_bo_vm_access,
     447             : };
     448             : 
     449           0 : int ttm_bo_mmap_obj(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
     450             : {
     451             :         /* Enforce no COW since would have really strange behavior with it. */
     452           0 :         if (is_cow_mapping(vma->vm_flags))
     453             :                 return -EINVAL;
     454             : 
     455           0 :         ttm_bo_get(bo);
     456             : 
     457             :         /*
     458             :          * Drivers may want to override the vm_ops field. Otherwise we
     459             :          * use TTM's default callbacks.
     460             :          */
     461           0 :         if (!vma->vm_ops)
     462           0 :                 vma->vm_ops = &ttm_bo_vm_ops;
     463             : 
     464             :         /*
     465             :          * Note: We're transferring the bo reference to
     466             :          * vma->vm_private_data here.
     467             :          */
     468             : 
     469           0 :         vma->vm_private_data = bo;
     470             : 
     471           0 :         vma->vm_flags |= VM_PFNMAP;
     472           0 :         vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
     473           0 :         return 0;
     474             : }
     475             : EXPORT_SYMBOL(ttm_bo_mmap_obj);

Generated by: LCOV version 1.14