Home | History | Annotate | Line # | Download | only in vmwgfx
vmwgfx_gmrid_manager.c revision 1.1.1.2.30.1
      1 /*	$NetBSD: vmwgfx_gmrid_manager.c,v 1.1.1.2.30.1 2019/06/10 22:08:29 christos Exp $	*/
      2 
      3 /**************************************************************************
      4  *
      5  * Copyright (c) 2007-2010 VMware, Inc., Palo Alto, CA., USA
      6  * All Rights Reserved.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the
     10  * "Software"), to deal in the Software without restriction, including
     11  * without limitation the rights to use, copy, modify, merge, publish,
     12  * distribute, sub license, and/or sell copies of the Software, and to
     13  * permit persons to whom the Software is furnished to do so, subject to
     14  * the following conditions:
     15  *
     16  * The above copyright notice and this permission notice (including the
     17  * next paragraph) shall be included in all copies or substantial portions
     18  * of the Software.
     19  *
     20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     23  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     24  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     25  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     26  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     27  *
     28  **************************************************************************/
     29 /*
     30  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: vmwgfx_gmrid_manager.c,v 1.1.1.2.30.1 2019/06/10 22:08:29 christos Exp $");
     35 
     36 #include "vmwgfx_drv.h"
     37 #include <drm/ttm/ttm_module.h>
     38 #include <drm/ttm/ttm_bo_driver.h>
     39 #include <drm/ttm/ttm_placement.h>
     40 #include <linux/idr.h>
     41 #include <linux/spinlock.h>
     42 #include <linux/kernel.h>
     43 
     44 struct vmwgfx_gmrid_man {
     45 	spinlock_t lock;
     46 	struct ida gmr_ida;
     47 	uint32_t max_gmr_ids;
     48 	uint32_t max_gmr_pages;
     49 	uint32_t used_gmr_pages;
     50 };
     51 
     52 static int vmw_gmrid_man_get_node(struct ttm_mem_type_manager *man,
     53 				  struct ttm_buffer_object *bo,
     54 				  const struct ttm_place *place,
     55 				  struct ttm_mem_reg *mem)
     56 {
     57 	struct vmwgfx_gmrid_man *gman =
     58 		(struct vmwgfx_gmrid_man *)man->priv;
     59 	int ret = 0;
     60 	int id;
     61 
     62 	mem->mm_node = NULL;
     63 
     64 	spin_lock(&gman->lock);
     65 
     66 	if (gman->max_gmr_pages > 0) {
     67 		gman->used_gmr_pages += bo->num_pages;
     68 		if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages))
     69 			goto out_err_locked;
     70 	}
     71 
     72 	do {
     73 		spin_unlock(&gman->lock);
     74 		if (unlikely(ida_pre_get(&gman->gmr_ida, GFP_KERNEL) == 0)) {
     75 			ret = -ENOMEM;
     76 			goto out_err;
     77 		}
     78 		spin_lock(&gman->lock);
     79 
     80 		ret = ida_get_new(&gman->gmr_ida, &id);
     81 		if (unlikely(ret == 0 && id >= gman->max_gmr_ids)) {
     82 			ida_remove(&gman->gmr_ida, id);
     83 			ret = 0;
     84 			goto out_err_locked;
     85 		}
     86 	} while (ret == -EAGAIN);
     87 
     88 	if (likely(ret == 0)) {
     89 		mem->mm_node = gman;
     90 		mem->start = id;
     91 		mem->num_pages = bo->num_pages;
     92 	} else
     93 		goto out_err_locked;
     94 
     95 	spin_unlock(&gman->lock);
     96 	return 0;
     97 
     98 out_err:
     99 	spin_lock(&gman->lock);
    100 out_err_locked:
    101 	gman->used_gmr_pages -= bo->num_pages;
    102 	spin_unlock(&gman->lock);
    103 	return ret;
    104 }
    105 
    106 static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
    107 				   struct ttm_mem_reg *mem)
    108 {
    109 	struct vmwgfx_gmrid_man *gman =
    110 		(struct vmwgfx_gmrid_man *)man->priv;
    111 
    112 	if (mem->mm_node) {
    113 		spin_lock(&gman->lock);
    114 		ida_remove(&gman->gmr_ida, mem->start);
    115 		gman->used_gmr_pages -= mem->num_pages;
    116 		spin_unlock(&gman->lock);
    117 		mem->mm_node = NULL;
    118 	}
    119 }
    120 
    121 static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
    122 			      unsigned long p_size)
    123 {
    124 	struct vmw_private *dev_priv =
    125 		container_of(man->bdev, struct vmw_private, bdev);
    126 	struct vmwgfx_gmrid_man *gman =
    127 		kzalloc(sizeof(*gman), GFP_KERNEL);
    128 
    129 	if (unlikely(gman == NULL))
    130 		return -ENOMEM;
    131 
    132 	spin_lock_init(&gman->lock);
    133 	gman->used_gmr_pages = 0;
    134 	ida_init(&gman->gmr_ida);
    135 
    136 	switch (p_size) {
    137 	case VMW_PL_GMR:
    138 		gman->max_gmr_ids = dev_priv->max_gmr_ids;
    139 		gman->max_gmr_pages = dev_priv->max_gmr_pages;
    140 		break;
    141 	case VMW_PL_MOB:
    142 		gman->max_gmr_ids = VMWGFX_NUM_MOB;
    143 		gman->max_gmr_pages = dev_priv->max_mob_pages;
    144 		break;
    145 	default:
    146 		BUG();
    147 	}
    148 	man->priv = (void *) gman;
    149 	return 0;
    150 }
    151 
    152 static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
    153 {
    154 	struct vmwgfx_gmrid_man *gman =
    155 		(struct vmwgfx_gmrid_man *)man->priv;
    156 
    157 	if (gman) {
    158 		ida_destroy(&gman->gmr_ida);
    159 		kfree(gman);
    160 	}
    161 	return 0;
    162 }
    163 
    164 static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
    165 				const char *prefix)
    166 {
    167 	printk(KERN_INFO "%s: No debug info available for the GMR "
    168 	       "id manager.\n", prefix);
    169 }
    170 
    171 const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
    172 	vmw_gmrid_man_init,
    173 	vmw_gmrid_man_takedown,
    174 	vmw_gmrid_man_get_node,
    175 	vmw_gmrid_man_put_node,
    176 	vmw_gmrid_man_debug
    177 };
    178