Home | History | Annotate | Line # | Download | only in vmwgfx
vmwgfx_gmrid_manager.c revision 1.1
      1 /**************************************************************************
      2  *
      3  * Copyright (c) 2007-2010 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 #include "vmwgfx_drv.h"
     32 #include <drm/ttm/ttm_module.h>
     33 #include <drm/ttm/ttm_bo_driver.h>
     34 #include <drm/ttm/ttm_placement.h>
     35 #include <linux/idr.h>
     36 #include <linux/spinlock.h>
     37 #include <linux/kernel.h>
     38 
     39 struct vmwgfx_gmrid_man {
     40 	spinlock_t lock;
     41 	struct ida gmr_ida;
     42 	uint32_t max_gmr_ids;
     43 	uint32_t max_gmr_pages;
     44 	uint32_t used_gmr_pages;
     45 };
     46 
     47 static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
     48 				  struct ttm_buffer_object *bo,
     49 				  struct ttm_placement *placement,
     50 				  struct ttm_mem_reg *mem)
     51 {
     52 	struct vmwgfx_gmrid_man *gman =
     53 		(struct vmwgfx_gmrid_man *)man->priv;
     54 	int ret = 0;
     55 	int id;
     56 
     57 	mem->mm_node = NULL;
     58 
     59 	spin_lock(&gman->lock);
     60 
     61 	if (gman->max_gmr_pages > 0) {
     62 		gman->used_gmr_pages += bo->num_pages;
     63 		if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages))
     64 			goto out_err_locked;
     65 	}
     66 
     67 	do {
     68 		spin_unlock(&gman->lock);
     69 		if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0)) {
     70 			ret = -ENOMEM;
     71 			goto out_err;
     72 		}
     73 		spin_lock(&gman->lock);
     74 
     75 		ret = ida_get_new(&gman->gmr_ida, &id);
     76 		if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) {
     77 			ida_remove(&gman->gmr_ida, id);
     78 			ret = 0;
     79 			goto out_err_locked;
     80 		}
     81 	} while (ret == -EAGAIN);
     82 
     83 	if (likely(ret == 0)) {
     84 		mem->mm_node = gman;
     85 		mem->start = id;
     86 		mem->num_pages = bo->num_pages;
     87 	} else
     88 		goto out_err_locked;
     89 
     90 	spin_unlock(&gman->lock);
     91 	return 0;
     92 
     93 out_err:
     94 	spin_lock(&gman->lock);
     95 out_err_locked:
     96 	gman->used_gmr_pages -= bo->num_pages;
     97 	spin_unlock(&gman->lock);
     98 	return ret;
     99 }
    100 
    101 static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
    102 				   struct ttm_mem_reg *mem)
    103 {
    104 	struct vmwgfx_gmrid_man *gman =
    105 		(struct vmwgfx_gmrid_man *)man->priv;
    106 
    107 	if (mem->mm_node) {
    108 		spin_lock(&gman->lock);
    109 		ida_remove(&gman->gmr_ida, mem->start);
    110 		gman->used_gmr_pages -= mem->num_pages;
    111 		spin_unlock(&gman->lock);
    112 		mem->mm_node = NULL;
    113 	}
    114 }
    115 
    116 static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
    117 			      unsigned long p_size)
    118 {
    119 	struct vmw_private *dev_priv =
    120 		container_of(man->bdev, struct vmw_private, bdev);
    121 	struct vmwgfx_gmrid_man *gman =
    122 		kzalloc(sizeof(*gman), GFP_KERNEL);
    123 
    124 	if (unlikely(gman == NULL))
    125 		return -ENOMEM;
    126 
    127 	spin_lock_init(&gman->lock);
    128 	gman->max_gmr_pages = dev_priv->max_gmr_pages;
    129 	gman->used_gmr_pages = 0;
    130 	ida_init(&gman->gmr_ida);
    131 	gman->max_gmr_ids = p_size;
    132 	man->priv = (void *) gman;
    133 	return 0;
    134 }
    135 
    136 static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
    137 {
    138 	struct vmwgfx_gmrid_man *gman =
    139 		(struct vmwgfx_gmrid_man *)man->priv;
    140 
    141 	if (gman) {
    142 		ida_destroy(&gman->gmr_ida);
    143 		kfree(gman);
    144 	}
    145 	return 0;
    146 }
    147 
    148 static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
    149 				const char *prefix)
    150 {
    151 	printk(KERN_INFO "%s: No debug info available for the GMR "
    152 	       "id manager.\n", prefix);
    153 }
    154 
    155 const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
    156 	vmw_gmrid_man_init,
    157 	vmw_gmrid_man_takedown,
    158 	vmw_gmrid_man_get_node,
    159 	vmw_gmrid_man_put_node,
    160 	vmw_gmrid_man_debug
    161 };
    162