cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ttm_range_manager.c (5859B)


      1/* SPDX-License-Identifier: GPL-2.0 OR MIT */
      2/**************************************************************************
      3 *
      4 * Copyright (c) 2007-2010 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#include <drm/ttm/ttm_device.h>
     33#include <drm/ttm/ttm_placement.h>
     34#include <drm/ttm/ttm_range_manager.h>
     35#include <drm/ttm/ttm_bo_api.h>
     36#include <drm/drm_mm.h>
     37#include <linux/slab.h>
     38#include <linux/spinlock.h>
     39
     40/*
     41 * Currently we use a spinlock for the lock, but a mutex *may* be
     42 * more appropriate to reduce scheduling latency if the range manager
     43 * ends up with very fragmented allocation patterns.
     44 */
     45
     46struct ttm_range_manager {
     47	struct ttm_resource_manager manager;
     48	struct drm_mm mm;
     49	spinlock_t lock;
     50};
     51
     52static inline struct ttm_range_manager *
     53to_range_manager(struct ttm_resource_manager *man)
     54{
     55	return container_of(man, struct ttm_range_manager, manager);
     56}
     57
     58static int ttm_range_man_alloc(struct ttm_resource_manager *man,
     59			       struct ttm_buffer_object *bo,
     60			       const struct ttm_place *place,
     61			       struct ttm_resource **res)
     62{
     63	struct ttm_range_manager *rman = to_range_manager(man);
     64	struct ttm_range_mgr_node *node;
     65	struct drm_mm *mm = &rman->mm;
     66	enum drm_mm_insert_mode mode;
     67	unsigned long lpfn;
     68	int ret;
     69
     70	lpfn = place->lpfn;
     71	if (!lpfn)
     72		lpfn = man->size;
     73
     74	node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL);
     75	if (!node)
     76		return -ENOMEM;
     77
     78	mode = DRM_MM_INSERT_BEST;
     79	if (place->flags & TTM_PL_FLAG_TOPDOWN)
     80		mode = DRM_MM_INSERT_HIGH;
     81
     82	ttm_resource_init(bo, place, &node->base);
     83
     84	spin_lock(&rman->lock);
     85	ret = drm_mm_insert_node_in_range(mm, &node->mm_nodes[0],
     86					  node->base.num_pages,
     87					  bo->page_alignment, 0,
     88					  place->fpfn, lpfn, mode);
     89	spin_unlock(&rman->lock);
     90
     91	if (unlikely(ret)) {
     92		ttm_resource_fini(man, &node->base);
     93		kfree(node);
     94		return ret;
     95	}
     96
     97	node->base.start = node->mm_nodes[0].start;
     98	*res = &node->base;
     99	return 0;
    100}
    101
    102static void ttm_range_man_free(struct ttm_resource_manager *man,
    103			       struct ttm_resource *res)
    104{
    105	struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
    106	struct ttm_range_manager *rman = to_range_manager(man);
    107
    108	spin_lock(&rman->lock);
    109	drm_mm_remove_node(&node->mm_nodes[0]);
    110	spin_unlock(&rman->lock);
    111
    112	ttm_resource_fini(man, res);
    113	kfree(node);
    114}
    115
    116static void ttm_range_man_debug(struct ttm_resource_manager *man,
    117				struct drm_printer *printer)
    118{
    119	struct ttm_range_manager *rman = to_range_manager(man);
    120
    121	spin_lock(&rman->lock);
    122	drm_mm_print(&rman->mm, printer);
    123	spin_unlock(&rman->lock);
    124}
    125
    126static const struct ttm_resource_manager_func ttm_range_manager_func = {
    127	.alloc = ttm_range_man_alloc,
    128	.free = ttm_range_man_free,
    129	.debug = ttm_range_man_debug
    130};
    131
    132/**
    133 * ttm_range_man_init_nocheck - Initialise a generic range manager for the
    134 * selected memory type.
    135 *
    136 * @bdev: ttm device
    137 * @type: memory manager type
    138 * @use_tt: if the memory manager uses tt
    139 * @p_size: size of area to be managed in pages.
    140 *
    141 * The range manager is installed for this device in the type slot.
    142 *
    143 * Return: %0 on success or a negative error code on failure
    144 */
    145int ttm_range_man_init_nocheck(struct ttm_device *bdev,
    146		       unsigned type, bool use_tt,
    147		       unsigned long p_size)
    148{
    149	struct ttm_resource_manager *man;
    150	struct ttm_range_manager *rman;
    151
    152	rman = kzalloc(sizeof(*rman), GFP_KERNEL);
    153	if (!rman)
    154		return -ENOMEM;
    155
    156	man = &rman->manager;
    157	man->use_tt = use_tt;
    158
    159	man->func = &ttm_range_manager_func;
    160
    161	ttm_resource_manager_init(man, bdev, p_size);
    162
    163	drm_mm_init(&rman->mm, 0, p_size);
    164	spin_lock_init(&rman->lock);
    165
    166	ttm_set_driver_manager(bdev, type, &rman->manager);
    167	ttm_resource_manager_set_used(man, true);
    168	return 0;
    169}
    170EXPORT_SYMBOL(ttm_range_man_init_nocheck);
    171
    172/**
    173 * ttm_range_man_fini_nocheck - Remove the generic range manager from a slot
    174 * and tear it down.
    175 *
    176 * @bdev: ttm device
    177 * @type: memory manager type
    178 *
    179 * Return: %0 on success or a negative error code on failure
    180 */
    181int ttm_range_man_fini_nocheck(struct ttm_device *bdev,
    182		       unsigned type)
    183{
    184	struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
    185	struct ttm_range_manager *rman = to_range_manager(man);
    186	struct drm_mm *mm = &rman->mm;
    187	int ret;
    188
    189	if (!man)
    190		return 0;
    191
    192	ttm_resource_manager_set_used(man, false);
    193
    194	ret = ttm_resource_manager_evict_all(bdev, man);
    195	if (ret)
    196		return ret;
    197
    198	spin_lock(&rman->lock);
    199	drm_mm_clean(mm);
    200	drm_mm_takedown(mm);
    201	spin_unlock(&rman->lock);
    202
    203	ttm_resource_manager_cleanup(man);
    204	ttm_set_driver_manager(bdev, type, NULL);
    205	kfree(rman);
    206	return 0;
    207}
    208EXPORT_SYMBOL(ttm_range_man_fini_nocheck);