The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/drm2/ttm/ttm_tt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /**************************************************************************
    2  *
    3  * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
    4  * All Rights Reserved.
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the
    8  * "Software"), to deal in the Software without restriction, including
    9  * without limitation the rights to use, copy, modify, merge, publish,
   10  * distribute, sub license, and/or sell copies of the Software, and to
   11  * permit persons to whom the Software is furnished to do so, subject to
   12  * the following conditions:
   13  *
   14  * The above copyright notice and this permission notice (including the
   15  * next paragraph) shall be included in all copies or substantial portions
   16  * of the Software.
   17  *
   18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
   21  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
   22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
   23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
   24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
   25  *
   26  **************************************************************************/
   27 /*
   28  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
   29  */
   30 /*
   31  * Copyright (c) 2013 The FreeBSD Foundation
   32  * All rights reserved.
   33  *
   34  * Portions of this software were developed by Konstantin Belousov
   35  * <kib@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD$");
   40 
   41 #include <dev/drm2/drmP.h>
   42 #include <dev/drm2/ttm/ttm_module.h>
   43 #include <dev/drm2/ttm/ttm_bo_driver.h>
   44 #include <dev/drm2/ttm/ttm_placement.h>
   45 #include <dev/drm2/ttm/ttm_page_alloc.h>
   46 
   47 MALLOC_DEFINE(M_TTM_PD, "ttm_pd", "TTM Page Directories");
   48 
   49 /**
   50  * Allocates storage for pointers to the pages that back the ttm.
   51  */
   52 static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm)
   53 {
   54         ttm->pages = malloc(ttm->num_pages * sizeof(void *),
   55             M_TTM_PD, M_WAITOK | M_ZERO);
   56 }
   57 
   58 static void ttm_dma_tt_alloc_page_directory(struct ttm_dma_tt *ttm)
   59 {
   60         ttm->ttm.pages = malloc(ttm->ttm.num_pages * sizeof(void *),
   61             M_TTM_PD, M_WAITOK | M_ZERO);
   62         ttm->dma_address = malloc(ttm->ttm.num_pages *
   63             sizeof(*ttm->dma_address), M_TTM_PD, M_WAITOK);
   64 }
   65 
   66 #if defined(__i386__) || defined(__amd64__)
   67 static inline int ttm_tt_set_page_caching(vm_page_t p,
   68                                           enum ttm_caching_state c_old,
   69                                           enum ttm_caching_state c_new)
   70 {
   71 
   72         /* XXXKIB our VM does not need this. */
   73 #if 0
   74         if (c_old != tt_cached) {
   75                 /* p isn't in the default caching state, set it to
   76                  * writeback first to free its current memtype. */
   77                 pmap_page_set_memattr(p, VM_MEMATTR_WRITE_BACK);
   78         }
   79 #endif
   80 
   81         if (c_new == tt_wc)
   82                 pmap_page_set_memattr(p, VM_MEMATTR_WRITE_COMBINING);
   83         else if (c_new == tt_uncached)
   84                 pmap_page_set_memattr(p, VM_MEMATTR_UNCACHEABLE);
   85 
   86         return (0);
   87 }
   88 #else
   89 static inline int ttm_tt_set_page_caching(vm_page_t p,
   90                                           enum ttm_caching_state c_old,
   91                                           enum ttm_caching_state c_new)
   92 {
   93         return 0;
   94 }
   95 #endif
   96 
   97 /*
   98  * Change caching policy for the linear kernel map
   99  * for range of pages in a ttm.
  100  */
  101 
  102 static int ttm_tt_set_caching(struct ttm_tt *ttm,
  103                               enum ttm_caching_state c_state)
  104 {
  105         int i, j;
  106         vm_page_t cur_page;
  107         int ret;
  108 
  109         if (ttm->caching_state == c_state)
  110                 return 0;
  111 
  112         if (ttm->state == tt_unpopulated) {
  113                 /* Change caching but don't populate */
  114                 ttm->caching_state = c_state;
  115                 return 0;
  116         }
  117 
  118         if (ttm->caching_state == tt_cached)
  119                 drm_clflush_pages(ttm->pages, ttm->num_pages);
  120 
  121         for (i = 0; i < ttm->num_pages; ++i) {
  122                 cur_page = ttm->pages[i];
  123                 if (likely(cur_page != NULL)) {
  124                         ret = ttm_tt_set_page_caching(cur_page,
  125                                                       ttm->caching_state,
  126                                                       c_state);
  127                         if (unlikely(ret != 0))
  128                                 goto out_err;
  129                 }
  130         }
  131 
  132         ttm->caching_state = c_state;
  133 
  134         return 0;
  135 
  136 out_err:
  137         for (j = 0; j < i; ++j) {
  138                 cur_page = ttm->pages[j];
  139                 if (cur_page != NULL) {
  140                         (void)ttm_tt_set_page_caching(cur_page, c_state,
  141                                                       ttm->caching_state);
  142                 }
  143         }
  144 
  145         return ret;
  146 }
  147 
  148 int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement)
  149 {
  150         enum ttm_caching_state state;
  151 
  152         if (placement & TTM_PL_FLAG_WC)
  153                 state = tt_wc;
  154         else if (placement & TTM_PL_FLAG_UNCACHED)
  155                 state = tt_uncached;
  156         else
  157                 state = tt_cached;
  158 
  159         return ttm_tt_set_caching(ttm, state);
  160 }
  161 
  162 void ttm_tt_destroy(struct ttm_tt *ttm)
  163 {
  164         if (unlikely(ttm == NULL))
  165                 return;
  166 
  167         if (ttm->state == tt_bound) {
  168                 ttm_tt_unbind(ttm);
  169         }
  170 
  171         if (likely(ttm->pages != NULL)) {
  172                 ttm->bdev->driver->ttm_tt_unpopulate(ttm);
  173         }
  174 
  175         if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP) &&
  176             ttm->swap_storage)
  177                 vm_object_deallocate(ttm->swap_storage);
  178 
  179         ttm->swap_storage = NULL;
  180         ttm->func->destroy(ttm);
  181 }
  182 
  183 int ttm_tt_init(struct ttm_tt *ttm, struct ttm_bo_device *bdev,
  184                 unsigned long size, uint32_t page_flags,
  185                 vm_page_t dummy_read_page)
  186 {
  187         ttm->bdev = bdev;
  188         ttm->glob = bdev->glob;
  189         ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
  190         ttm->caching_state = tt_cached;
  191         ttm->page_flags = page_flags;
  192         ttm->dummy_read_page = dummy_read_page;
  193         ttm->state = tt_unpopulated;
  194         ttm->swap_storage = NULL;
  195 
  196         ttm_tt_alloc_page_directory(ttm);
  197         if (!ttm->pages) {
  198                 ttm_tt_destroy(ttm);
  199                 printf("Failed allocating page table\n");
  200                 return -ENOMEM;
  201         }
  202         return 0;
  203 }
  204 
  205 void ttm_tt_fini(struct ttm_tt *ttm)
  206 {
  207         free(ttm->pages, M_TTM_PD);
  208         ttm->pages = NULL;
  209 }
  210 
  211 int ttm_dma_tt_init(struct ttm_dma_tt *ttm_dma, struct ttm_bo_device *bdev,
  212                 unsigned long size, uint32_t page_flags,
  213                 vm_page_t dummy_read_page)
  214 {
  215         struct ttm_tt *ttm = &ttm_dma->ttm;
  216 
  217         ttm->bdev = bdev;
  218         ttm->glob = bdev->glob;
  219         ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
  220         ttm->caching_state = tt_cached;
  221         ttm->page_flags = page_flags;
  222         ttm->dummy_read_page = dummy_read_page;
  223         ttm->state = tt_unpopulated;
  224         ttm->swap_storage = NULL;
  225 
  226         INIT_LIST_HEAD(&ttm_dma->pages_list);
  227         ttm_dma_tt_alloc_page_directory(ttm_dma);
  228         if (!ttm->pages || !ttm_dma->dma_address) {
  229                 ttm_tt_destroy(ttm);
  230                 printf("Failed allocating page table\n");
  231                 return -ENOMEM;
  232         }
  233         return 0;
  234 }
  235 
  236 void ttm_dma_tt_fini(struct ttm_dma_tt *ttm_dma)
  237 {
  238         struct ttm_tt *ttm = &ttm_dma->ttm;
  239 
  240         free(ttm->pages, M_TTM_PD);
  241         ttm->pages = NULL;
  242         free(ttm_dma->dma_address, M_TTM_PD);
  243         ttm_dma->dma_address = NULL;
  244 }
  245 
  246 void ttm_tt_unbind(struct ttm_tt *ttm)
  247 {
  248         int ret;
  249 
  250         if (ttm->state == tt_bound) {
  251                 ret = ttm->func->unbind(ttm);
  252                 MPASS(ret == 0);
  253                 ttm->state = tt_unbound;
  254         }
  255 }
  256 
  257 int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
  258 {
  259         int ret = 0;
  260 
  261         if (!ttm)
  262                 return -EINVAL;
  263 
  264         if (ttm->state == tt_bound)
  265                 return 0;
  266 
  267         ret = ttm->bdev->driver->ttm_tt_populate(ttm);
  268         if (ret)
  269                 return ret;
  270 
  271         ret = ttm->func->bind(ttm, bo_mem);
  272         if (unlikely(ret != 0))
  273                 return ret;
  274 
  275         ttm->state = tt_bound;
  276 
  277         return 0;
  278 }
  279 
  280 int ttm_tt_swapin(struct ttm_tt *ttm)
  281 {
  282         vm_object_t obj;
  283         vm_page_t from_page, to_page;
  284         int i, ret, rv;
  285 
  286         obj = ttm->swap_storage;
  287 
  288         vm_object_pip_add(obj, 1);
  289         for (i = 0; i < ttm->num_pages; ++i) {
  290                 rv = vm_page_grab_valid_unlocked(&from_page, obj, i,
  291                     VM_ALLOC_NORMAL | VM_ALLOC_SBUSY | VM_ALLOC_IGN_SBUSY);
  292                 if (rv != VM_PAGER_OK) {
  293                         ret = -EIO;
  294                         goto err_ret;
  295                 }
  296                 to_page = ttm->pages[i];
  297                 if (unlikely(to_page == NULL)) {
  298                         vm_page_sunbusy(from_page);
  299                         ret = -ENOMEM;
  300                         goto err_ret;
  301                 }
  302                 pmap_copy_page(from_page, to_page);
  303                 vm_page_sunbusy(from_page);
  304         }
  305         vm_object_pip_wakeup(obj);
  306 
  307         if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP))
  308                 vm_object_deallocate(obj);
  309         ttm->swap_storage = NULL;
  310         ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED;
  311         return (0);
  312 
  313 err_ret:
  314         vm_object_pip_wakeup(obj);
  315         return (ret);
  316 }
  317 
  318 int ttm_tt_swapout(struct ttm_tt *ttm, vm_object_t persistent_swap_storage)
  319 {
  320         vm_object_t obj;
  321         vm_page_t from_page, to_page;
  322         int i;
  323 
  324         MPASS(ttm->state == tt_unbound || ttm->state == tt_unpopulated);
  325         MPASS(ttm->caching_state == tt_cached);
  326 
  327         if (persistent_swap_storage == NULL) {
  328                 obj = vm_pager_allocate(OBJT_SWAP, NULL,
  329                     IDX_TO_OFF(ttm->num_pages), VM_PROT_DEFAULT, 0,
  330                     curthread->td_ucred);
  331                 if (obj == NULL) {
  332                         printf("[TTM] Failed allocating swap storage\n");
  333                         return (-ENOMEM);
  334                 }
  335         } else
  336                 obj = persistent_swap_storage;
  337 
  338         VM_OBJECT_WLOCK(obj);
  339         vm_object_pip_add(obj, 1);
  340         for (i = 0; i < ttm->num_pages; ++i) {
  341                 from_page = ttm->pages[i];
  342                 if (unlikely(from_page == NULL))
  343                         continue;
  344                 to_page = vm_page_grab(obj, i, VM_ALLOC_NORMAL);
  345                 pmap_copy_page(from_page, to_page);
  346                 vm_page_valid(to_page);
  347                 vm_page_dirty(to_page);
  348                 vm_page_xunbusy(to_page);
  349         }
  350         vm_object_pip_wakeup(obj);
  351         VM_OBJECT_WUNLOCK(obj);
  352 
  353         ttm->bdev->driver->ttm_tt_unpopulate(ttm);
  354         ttm->swap_storage = obj;
  355         ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED;
  356         if (persistent_swap_storage != NULL)
  357                 ttm->page_flags |= TTM_PAGE_FLAG_PERSISTENT_SWAP;
  358         return (0);
  359 }

Cache object: 5937549e9161e27634dfaf00c7cf66b9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.