Line data Source code
1 : /**************************************************************************
2 : *
3 : * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
4 : * All Rights Reserved.
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a
7 : * copy of this software and associated documentation files (the
8 : * "Software"), to deal in the Software without restriction, including
9 : * without limitation the rights to use, copy, modify, merge, publish,
10 : * distribute, sub license, and/or sell copies of the Software, and to
11 : * permit persons to whom the Software is furnished to do so, subject to
12 : * the following conditions:
13 : *
14 : * The above copyright notice and this permission notice (including the
15 : * next paragraph) shall be included in all copies or substantial portions
16 : * of the Software.
17 : *
18 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 : * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 : * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 : * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 : * USE OR OTHER DEALINGS IN THE SOFTWARE.
25 : *
26 : **************************************************************************/
27 :
28 : #include <dev/pci/drm/ttm/ttm_execbuf_util.h>
29 : #include <dev/pci/drm/ttm/ttm_bo_driver.h>
30 : #include <dev/pci/drm/ttm/ttm_placement.h>
31 :
32 0 : static void ttm_eu_backoff_reservation_reverse(struct list_head *list,
33 : struct ttm_validate_buffer *entry)
34 : {
35 0 : list_for_each_entry_continue_reverse(entry, list, head) {
36 0 : struct ttm_buffer_object *bo = entry->bo;
37 :
38 0 : __ttm_bo_unreserve(bo);
39 : }
40 0 : }
41 :
42 0 : static void ttm_eu_del_from_lru_locked(struct list_head *list)
43 : {
44 : struct ttm_validate_buffer *entry;
45 :
46 0 : list_for_each_entry(entry, list, head) {
47 0 : struct ttm_buffer_object *bo = entry->bo;
48 0 : unsigned put_count = ttm_bo_del_from_lru(bo);
49 :
50 0 : ttm_bo_list_ref_sub(bo, put_count, true);
51 : }
52 0 : }
53 :
54 0 : void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
55 : struct list_head *list)
56 : {
57 : struct ttm_validate_buffer *entry;
58 : struct ttm_bo_global *glob;
59 :
60 0 : if (list_empty(list))
61 0 : return;
62 :
63 0 : entry = list_first_entry(list, struct ttm_validate_buffer, head);
64 0 : glob = entry->bo->glob;
65 :
66 0 : spin_lock(&glob->lru_lock);
67 0 : list_for_each_entry(entry, list, head) {
68 0 : struct ttm_buffer_object *bo = entry->bo;
69 :
70 0 : ttm_bo_add_to_lru(bo);
71 0 : __ttm_bo_unreserve(bo);
72 : }
73 0 : spin_unlock(&glob->lru_lock);
74 :
75 0 : if (ticket)
76 0 : ww_acquire_fini(ticket);
77 0 : }
78 : EXPORT_SYMBOL(ttm_eu_backoff_reservation);
79 :
80 : /*
81 : * Reserve buffers for validation.
82 : *
83 : * If a buffer in the list is marked for CPU access, we back off and
84 : * wait for that buffer to become free for GPU access.
85 : *
86 : * If a buffer is reserved for another validation, the validator with
87 : * the highest validation sequence backs off and waits for that buffer
88 : * to become unreserved. This prevents deadlocks when validating multiple
89 : * buffers in different orders.
90 : */
91 :
92 0 : int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
93 : struct list_head *list, bool intr,
94 : struct list_head *dups)
95 : {
96 : struct ttm_bo_global *glob;
97 : struct ttm_validate_buffer *entry;
98 : int ret;
99 :
100 0 : if (list_empty(list))
101 0 : return 0;
102 :
103 0 : entry = list_first_entry(list, struct ttm_validate_buffer, head);
104 0 : glob = entry->bo->glob;
105 :
106 0 : if (ticket)
107 0 : ww_acquire_init(ticket, &reservation_ww_class);
108 :
109 0 : list_for_each_entry(entry, list, head) {
110 0 : struct ttm_buffer_object *bo = entry->bo;
111 :
112 0 : ret = __ttm_bo_reserve(bo, intr, (ticket == NULL), true,
113 : ticket);
114 0 : if (!ret && unlikely(atomic_read(&bo->cpu_writers) > 0)) {
115 0 : __ttm_bo_unreserve(bo);
116 :
117 : ret = -EBUSY;
118 :
119 0 : } else if (ret == -EALREADY && dups) {
120 : struct ttm_validate_buffer *safe = entry;
121 0 : entry = list_prev_entry(entry, head);
122 0 : list_del(&safe->head);
123 0 : list_add(&safe->head, dups);
124 : continue;
125 : }
126 :
127 0 : if (!ret) {
128 0 : if (!entry->shared)
129 0 : continue;
130 :
131 0 : ret = reservation_object_reserve_shared(bo->resv);
132 0 : if (!ret)
133 0 : continue;
134 : }
135 :
136 : /* uh oh, we lost out, drop every reservation and try
137 : * to only reserve this buffer, then start over if
138 : * this succeeds.
139 : */
140 0 : ttm_eu_backoff_reservation_reverse(list, entry);
141 :
142 0 : if (ret == -EDEADLK && intr) {
143 0 : ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
144 : ticket);
145 0 : } else if (ret == -EDEADLK) {
146 0 : ww_mutex_lock_slow(&bo->resv->lock, ticket);
147 : ret = 0;
148 0 : }
149 :
150 0 : if (!ret && entry->shared)
151 0 : ret = reservation_object_reserve_shared(bo->resv);
152 :
153 0 : if (unlikely(ret != 0)) {
154 0 : if (ret == -EINTR)
155 0 : ret = -ERESTARTSYS;
156 0 : if (ticket) {
157 0 : ww_acquire_done(ticket);
158 0 : ww_acquire_fini(ticket);
159 0 : }
160 0 : return ret;
161 : }
162 :
163 : /* move this item to the front of the list,
164 : * forces correct iteration of the loop without keeping track
165 : */
166 0 : list_del(&entry->head);
167 0 : list_add(&entry->head, list);
168 0 : }
169 :
170 0 : if (ticket)
171 0 : ww_acquire_done(ticket);
172 0 : spin_lock(&glob->lru_lock);
173 0 : ttm_eu_del_from_lru_locked(list);
174 0 : spin_unlock(&glob->lru_lock);
175 0 : return 0;
176 0 : }
177 : EXPORT_SYMBOL(ttm_eu_reserve_buffers);
178 :
179 0 : void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
180 : struct list_head *list, struct fence *fence)
181 : {
182 : struct ttm_validate_buffer *entry;
183 : struct ttm_buffer_object *bo;
184 : struct ttm_bo_global *glob;
185 : struct ttm_bo_device *bdev;
186 : struct ttm_bo_driver *driver;
187 :
188 0 : if (list_empty(list))
189 0 : return;
190 :
191 0 : bo = list_first_entry(list, struct ttm_validate_buffer, head)->bo;
192 0 : bdev = bo->bdev;
193 0 : driver = bdev->driver;
194 0 : glob = bo->glob;
195 :
196 0 : spin_lock(&glob->lru_lock);
197 :
198 0 : list_for_each_entry(entry, list, head) {
199 0 : bo = entry->bo;
200 0 : if (entry->shared)
201 0 : reservation_object_add_shared_fence(bo->resv, fence);
202 : else
203 0 : reservation_object_add_excl_fence(bo->resv, fence);
204 0 : ttm_bo_add_to_lru(bo);
205 0 : __ttm_bo_unreserve(bo);
206 : }
207 0 : spin_unlock(&glob->lru_lock);
208 0 : if (ticket)
209 0 : ww_acquire_fini(ticket);
210 0 : }
211 : EXPORT_SYMBOL(ttm_eu_fence_buffer_objects);
|