Home | History | Annotate | Line # | Download | only in vmwgfx
      1 /*	$NetBSD: vmwgfx_gmrid_manager.c,v 1.3 2021/12/18 23:45:45 riastradh Exp $	*/
      2 
      3 // SPDX-License-Identifier: GPL-2.0 OR MIT
      4 /**************************************************************************
      5  *
      6  * Copyright 2007-2010 VMware, Inc., Palo Alto, CA., USA
      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.3 2021/12/18 23:45:45 riastradh 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 id;
     60 
     61 	mem->mm_node = NULL;
     62 
     63 	id = ida_alloc_max(&gman->gmr_ida, gman->max_gmr_ids - 1, GFP_KERNEL);
     64 	if (id < 0)
     65 		return (id != -ENOMEM ? 0 : id);
     66 
     67 	spin_lock(&gman->lock);
     68 
     69 	if (gman->max_gmr_pages > 0) {
     70 		gman->used_gmr_pages += bo->num_pages;
     71 		if (unlikely(gman->used_gmr_pages > gman->max_gmr_pages))
     72 			goto nospace;
     73 	}
     74 
     75 	mem->mm_node = gman;
     76 	mem->start = id;
     77 	mem->num_pages = bo->num_pages;
     78 
     79 	spin_unlock(&gman->lock);
     80 	return 0;
     81 
     82 nospace:
     83 	gman->used_gmr_pages -= bo->num_pages;
     84 	spin_unlock(&gman->lock);
     85 	ida_free(&gman->gmr_ida, id);
     86 	return 0;
     87 }
     88 
     89 static void vmw_gmrid_man_put_node(struct ttm_mem_type_manager *man,
     90 				   struct ttm_mem_reg *mem)
     91 {
     92 	struct vmwgfx_gmrid_man *gman =
     93 		(struct vmwgfx_gmrid_man *)man->priv;
     94 
     95 	if (mem->mm_node) {
     96 		ida_free(&gman->gmr_ida, mem->start);
     97 		spin_lock(&gman->lock);
     98 		gman->used_gmr_pages -= mem->num_pages;
     99 		spin_unlock(&gman->lock);
    100 		mem->mm_node = NULL;
    101 	}
    102 }
    103 
    104 static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
    105 			      unsigned long p_size)
    106 {
    107 	struct vmw_private *dev_priv =
    108 		container_of(man->bdev, struct vmw_private, bdev);
    109 	struct vmwgfx_gmrid_man *gman =
    110 		kzalloc(sizeof(*gman), GFP_KERNEL);
    111 
    112 	if (unlikely(!gman))
    113 		return -ENOMEM;
    114 
    115 	spin_lock_init(&gman->lock);
    116 	gman->used_gmr_pages = 0;
    117 	ida_init(&gman->gmr_ida);
    118 
    119 	switch (p_size) {
    120 	case VMW_PL_GMR:
    121 		gman->max_gmr_ids = dev_priv->max_gmr_ids;
    122 		gman->max_gmr_pages = dev_priv->max_gmr_pages;
    123 		break;
    124 	case VMW_PL_MOB:
    125 		gman->max_gmr_ids = VMWGFX_NUM_MOB;
    126 		gman->max_gmr_pages = dev_priv->max_mob_pages;
    127 		break;
    128 	default:
    129 		BUG();
    130 	}
    131 	man->priv = (void *) gman;
    132 	return 0;
    133 }
    134 
    135 static int vmw_gmrid_man_takedown(struct ttm_mem_type_manager *man)
    136 {
    137 	struct vmwgfx_gmrid_man *gman =
    138 		(struct vmwgfx_gmrid_man *)man->priv;
    139 
    140 	if (gman) {
    141 		ida_destroy(&gman->gmr_ida);
    142 		kfree(gman);
    143 	}
    144 	return 0;
    145 }
    146 
    147 static void vmw_gmrid_man_debug(struct ttm_mem_type_manager *man,
    148 				struct drm_printer *printer)
    149 {
    150 	drm_printf(printer, "No debug info available for the GMR id manager\n");
    151 }
    152 
    153 const struct ttm_mem_type_manager_func vmw_gmrid_manager_func = {
    154 	.init = vmw_gmrid_man_init,
    155 	.takedown = vmw_gmrid_man_takedown,
    156 	.get_node = vmw_gmrid_man_get_node,
    157 	.put_node = vmw_gmrid_man_put_node,
    158 	.debug = vmw_gmrid_man_debug
    159 };
    160