0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 #include <drm/ttm/ttm_device.h>
0033 #include <drm/ttm/ttm_placement.h>
0034 #include <drm/ttm/ttm_range_manager.h>
0035 #include <drm/ttm/ttm_bo_api.h>
0036 #include <drm/drm_mm.h>
0037 #include <linux/slab.h>
0038 #include <linux/spinlock.h>
0039
0040
0041
0042
0043
0044
0045
0046 struct ttm_range_manager {
0047 struct ttm_resource_manager manager;
0048 struct drm_mm mm;
0049 spinlock_t lock;
0050 };
0051
0052 static inline struct ttm_range_manager *
0053 to_range_manager(struct ttm_resource_manager *man)
0054 {
0055 return container_of(man, struct ttm_range_manager, manager);
0056 }
0057
0058 static int ttm_range_man_alloc(struct ttm_resource_manager *man,
0059 struct ttm_buffer_object *bo,
0060 const struct ttm_place *place,
0061 struct ttm_resource **res)
0062 {
0063 struct ttm_range_manager *rman = to_range_manager(man);
0064 struct ttm_range_mgr_node *node;
0065 struct drm_mm *mm = &rman->mm;
0066 enum drm_mm_insert_mode mode;
0067 unsigned long lpfn;
0068 int ret;
0069
0070 lpfn = place->lpfn;
0071 if (!lpfn)
0072 lpfn = man->size;
0073
0074 node = kzalloc(struct_size(node, mm_nodes, 1), GFP_KERNEL);
0075 if (!node)
0076 return -ENOMEM;
0077
0078 mode = DRM_MM_INSERT_BEST;
0079 if (place->flags & TTM_PL_FLAG_TOPDOWN)
0080 mode = DRM_MM_INSERT_HIGH;
0081
0082 ttm_resource_init(bo, place, &node->base);
0083
0084 spin_lock(&rman->lock);
0085 ret = drm_mm_insert_node_in_range(mm, &node->mm_nodes[0],
0086 node->base.num_pages,
0087 bo->page_alignment, 0,
0088 place->fpfn, lpfn, mode);
0089 spin_unlock(&rman->lock);
0090
0091 if (unlikely(ret)) {
0092 ttm_resource_fini(man, &node->base);
0093 kfree(node);
0094 return ret;
0095 }
0096
0097 node->base.start = node->mm_nodes[0].start;
0098 *res = &node->base;
0099 return 0;
0100 }
0101
0102 static void ttm_range_man_free(struct ttm_resource_manager *man,
0103 struct ttm_resource *res)
0104 {
0105 struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
0106 struct ttm_range_manager *rman = to_range_manager(man);
0107
0108 spin_lock(&rman->lock);
0109 drm_mm_remove_node(&node->mm_nodes[0]);
0110 spin_unlock(&rman->lock);
0111
0112 ttm_resource_fini(man, res);
0113 kfree(node);
0114 }
0115
0116 static void ttm_range_man_debug(struct ttm_resource_manager *man,
0117 struct drm_printer *printer)
0118 {
0119 struct ttm_range_manager *rman = to_range_manager(man);
0120
0121 spin_lock(&rman->lock);
0122 drm_mm_print(&rman->mm, printer);
0123 spin_unlock(&rman->lock);
0124 }
0125
0126 static const struct ttm_resource_manager_func ttm_range_manager_func = {
0127 .alloc = ttm_range_man_alloc,
0128 .free = ttm_range_man_free,
0129 .debug = ttm_range_man_debug
0130 };
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 int ttm_range_man_init_nocheck(struct ttm_device *bdev,
0146 unsigned type, bool use_tt,
0147 unsigned long p_size)
0148 {
0149 struct ttm_resource_manager *man;
0150 struct ttm_range_manager *rman;
0151
0152 rman = kzalloc(sizeof(*rman), GFP_KERNEL);
0153 if (!rman)
0154 return -ENOMEM;
0155
0156 man = &rman->manager;
0157 man->use_tt = use_tt;
0158
0159 man->func = &ttm_range_manager_func;
0160
0161 ttm_resource_manager_init(man, bdev, p_size);
0162
0163 drm_mm_init(&rman->mm, 0, p_size);
0164 spin_lock_init(&rman->lock);
0165
0166 ttm_set_driver_manager(bdev, type, &rman->manager);
0167 ttm_resource_manager_set_used(man, true);
0168 return 0;
0169 }
0170 EXPORT_SYMBOL(ttm_range_man_init_nocheck);
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 int ttm_range_man_fini_nocheck(struct ttm_device *bdev,
0182 unsigned type)
0183 {
0184 struct ttm_resource_manager *man = ttm_manager_type(bdev, type);
0185 struct ttm_range_manager *rman = to_range_manager(man);
0186 struct drm_mm *mm = &rman->mm;
0187 int ret;
0188
0189 if (!man)
0190 return 0;
0191
0192 ttm_resource_manager_set_used(man, false);
0193
0194 ret = ttm_resource_manager_evict_all(bdev, man);
0195 if (ret)
0196 return ret;
0197
0198 spin_lock(&rman->lock);
0199 drm_mm_clean(mm);
0200 drm_mm_takedown(mm);
0201 spin_unlock(&rman->lock);
0202
0203 ttm_resource_manager_cleanup(man);
0204 ttm_set_driver_manager(bdev, type, NULL);
0205 kfree(rman);
0206 return 0;
0207 }
0208 EXPORT_SYMBOL(ttm_range_man_fini_nocheck);