aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/radeon
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2015-03-31 11:37:00 -0400
committerAlex Deucher <alexander.deucher@amd.com>2015-04-13 11:17:59 -0400
commit49ecb10e01c68b05dcb73005a54430c15caa05d0 (patch)
treec9dc7e1118cfebfd49de26ee60b8849b84d75211 /drivers/gpu/drm/radeon
parentc6a1fc725a847b75be9bd0d1e91d0e1c529ad93f (diff)
drm/radeon: allow creating overlapping userptrs
Similar to the Intel implementation, but instead of just falling back to a global linear list when we have an overlapping userptr request we accumulate all overlapping userptrs in a local list. Signed-off-by: Christian König <christian.koenig@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon')
-rw-r--r--drivers/gpu/drm/radeon/radeon.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_mn.c102
2 files changed, 76 insertions, 28 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 73a6432da1a5..d2abe481954f 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -507,7 +507,7 @@ struct radeon_bo {
507 pid_t pid; 507 pid_t pid;
508 508
509 struct radeon_mn *mn; 509 struct radeon_mn *mn;
510 struct interval_tree_node mn_it; 510 struct list_head mn_list;
511}; 511};
512#define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base) 512#define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base)
513 513
diff --git a/drivers/gpu/drm/radeon/radeon_mn.c b/drivers/gpu/drm/radeon/radeon_mn.c
index 572b4dbec186..01701376b239 100644
--- a/drivers/gpu/drm/radeon/radeon_mn.c
+++ b/drivers/gpu/drm/radeon/radeon_mn.c
@@ -53,6 +53,11 @@ struct radeon_mn {
53 struct rb_root objects; 53 struct rb_root objects;
54}; 54};
55 55
56struct radeon_mn_node {
57 struct interval_tree_node it;
58 struct list_head bos;
59};
60
56/** 61/**
57 * radeon_mn_destroy - destroy the rmn 62 * radeon_mn_destroy - destroy the rmn
58 * 63 *
@@ -64,14 +69,21 @@ static void radeon_mn_destroy(struct work_struct *work)
64{ 69{
65 struct radeon_mn *rmn = container_of(work, struct radeon_mn, work); 70 struct radeon_mn *rmn = container_of(work, struct radeon_mn, work);
66 struct radeon_device *rdev = rmn->rdev; 71 struct radeon_device *rdev = rmn->rdev;
67 struct radeon_bo *bo, *next; 72 struct radeon_mn_node *node, *next_node;
73 struct radeon_bo *bo, *next_bo;
68 74
69 mutex_lock(&rdev->mn_lock); 75 mutex_lock(&rdev->mn_lock);
70 mutex_lock(&rmn->lock); 76 mutex_lock(&rmn->lock);
71 hash_del(&rmn->node); 77 hash_del(&rmn->node);
72 rbtree_postorder_for_each_entry_safe(bo, next, &rmn->objects, mn_it.rb) { 78 rbtree_postorder_for_each_entry_safe(node, next_node, &rmn->objects,
73 interval_tree_remove(&bo->mn_it, &rmn->objects); 79 it.rb) {
74 bo->mn = NULL; 80
81 interval_tree_remove(&node->it, &rmn->objects);
82 list_for_each_entry_safe(bo, next_bo, &node->bos, mn_list) {
83 bo->mn = NULL;
84 list_del_init(&bo->mn_list);
85 }
86 kfree(node);
75 } 87 }
76 mutex_unlock(&rmn->lock); 88 mutex_unlock(&rmn->lock);
77 mutex_unlock(&rdev->mn_lock); 89 mutex_unlock(&rdev->mn_lock);
@@ -121,29 +133,33 @@ static void radeon_mn_invalidate_range_start(struct mmu_notifier *mn,
121 133
122 it = interval_tree_iter_first(&rmn->objects, start, end); 134 it = interval_tree_iter_first(&rmn->objects, start, end);
123 while (it) { 135 while (it) {
136 struct radeon_mn_node *node;
124 struct radeon_bo *bo; 137 struct radeon_bo *bo;
125 int r; 138 int r;
126 139
127 bo = container_of(it, struct radeon_bo, mn_it); 140 node = container_of(it, struct radeon_mn_node, it);
128 it = interval_tree_iter_next(it, start, end); 141 it = interval_tree_iter_next(it, start, end);
129 142
130 r = radeon_bo_reserve(bo, true); 143 list_for_each_entry(bo, &node->bos, mn_list) {
131 if (r) {
132 DRM_ERROR("(%d) failed to reserve user bo\n", r);
133 continue;
134 }
135 144
136 r = reservation_object_wait_timeout_rcu(bo->tbo.resv, true, 145 r = radeon_bo_reserve(bo, true);
137 false, MAX_SCHEDULE_TIMEOUT); 146 if (r) {
138 if (r) 147 DRM_ERROR("(%d) failed to reserve user bo\n", r);
139 DRM_ERROR("(%d) failed to wait for user bo\n", r); 148 continue;
149 }
140 150
141 radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU); 151 r = reservation_object_wait_timeout_rcu(bo->tbo.resv,
142 r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false); 152 true, false, MAX_SCHEDULE_TIMEOUT);
143 if (r) 153 if (r)
144 DRM_ERROR("(%d) failed to validate user bo\n", r); 154 DRM_ERROR("(%d) failed to wait for user bo\n", r);
145 155
146 radeon_bo_unreserve(bo); 156 radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_CPU);
157 r = ttm_bo_validate(&bo->tbo, &bo->placement, false, false);
158 if (r)
159 DRM_ERROR("(%d) failed to validate user bo\n", r);
160
161 radeon_bo_unreserve(bo);
162 }
147 } 163 }
148 164
149 mutex_unlock(&rmn->lock); 165 mutex_unlock(&rmn->lock);
@@ -220,24 +236,44 @@ int radeon_mn_register(struct radeon_bo *bo, unsigned long addr)
220 unsigned long end = addr + radeon_bo_size(bo) - 1; 236 unsigned long end = addr + radeon_bo_size(bo) - 1;
221 struct radeon_device *rdev = bo->rdev; 237 struct radeon_device *rdev = bo->rdev;
222 struct radeon_mn *rmn; 238 struct radeon_mn *rmn;
239 struct radeon_mn_node *node = NULL;
240 struct list_head bos;
223 struct interval_tree_node *it; 241 struct interval_tree_node *it;
224 242
225 rmn = radeon_mn_get(rdev); 243 rmn = radeon_mn_get(rdev);
226 if (IS_ERR(rmn)) 244 if (IS_ERR(rmn))
227 return PTR_ERR(rmn); 245 return PTR_ERR(rmn);
228 246
247 INIT_LIST_HEAD(&bos);
248
229 mutex_lock(&rmn->lock); 249 mutex_lock(&rmn->lock);
230 250
231 it = interval_tree_iter_first(&rmn->objects, addr, end); 251 while ((it = interval_tree_iter_first(&rmn->objects, addr, end))) {
232 if (it) { 252 kfree(node);
233 mutex_unlock(&rmn->lock); 253 node = container_of(it, struct radeon_mn_node, it);
234 return -EEXIST; 254 interval_tree_remove(&node->it, &rmn->objects);
255 addr = min(it->start, addr);
256 end = max(it->last, end);
257 list_splice(&node->bos, &bos);
258 }
259
260 if (!node) {
261 node = kmalloc(sizeof(struct radeon_mn_node), GFP_KERNEL);
262 if (!node) {
263 mutex_unlock(&rmn->lock);
264 return -ENOMEM;
265 }
235 } 266 }
236 267
237 bo->mn = rmn; 268 bo->mn = rmn;
238 bo->mn_it.start = addr; 269
239 bo->mn_it.last = end; 270 node->it.start = addr;
240 interval_tree_insert(&bo->mn_it, &rmn->objects); 271 node->it.last = end;
272 INIT_LIST_HEAD(&node->bos);
273 list_splice(&bos, &node->bos);
274 list_add(&bo->mn_list, &node->bos);
275
276 interval_tree_insert(&node->it, &rmn->objects);
241 277
242 mutex_unlock(&rmn->lock); 278 mutex_unlock(&rmn->lock);
243 279
@@ -255,6 +291,7 @@ void radeon_mn_unregister(struct radeon_bo *bo)
255{ 291{
256 struct radeon_device *rdev = bo->rdev; 292 struct radeon_device *rdev = bo->rdev;
257 struct radeon_mn *rmn; 293 struct radeon_mn *rmn;
294 struct list_head *head;
258 295
259 mutex_lock(&rdev->mn_lock); 296 mutex_lock(&rdev->mn_lock);
260 rmn = bo->mn; 297 rmn = bo->mn;
@@ -264,8 +301,19 @@ void radeon_mn_unregister(struct radeon_bo *bo)
264 } 301 }
265 302
266 mutex_lock(&rmn->lock); 303 mutex_lock(&rmn->lock);
267 interval_tree_remove(&bo->mn_it, &rmn->objects); 304 /* save the next list entry for later */
305 head = bo->mn_list.next;
306
268 bo->mn = NULL; 307 bo->mn = NULL;
308 list_del(&bo->mn_list);
309
310 if (list_empty(head)) {
311 struct radeon_mn_node *node;
312 node = container_of(head, struct radeon_mn_node, bos);
313 interval_tree_remove(&node->it, &rmn->objects);
314 kfree(node);
315 }
316
269 mutex_unlock(&rmn->lock); 317 mutex_unlock(&rmn->lock);
270 mutex_unlock(&rdev->mn_lock); 318 mutex_unlock(&rdev->mn_lock);
271} 319}