aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
diff options
context:
space:
mode:
authorThomas Hellstrom <thellstrom@vmware.com>2013-10-24 04:49:26 -0400
committerThomas Hellstrom <thellstrom@vmware.com>2013-11-06 06:57:16 -0500
commitd92d985177c495aab53c7167f310a7efb1853918 (patch)
treeb8af3af9373dd0bbcb7df30b5e5a7b66dbf98801 /drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
parent7aeb7448d8d02868ef30a6d08e856b2220319273 (diff)
drm/vmwgfx: Use the linux DMA api to get valid device addresses of pages
The code handles three different cases: 1) physical page addresses. The ttm page array is used. 2) DMA subsystem addresses. A scatter-gather list is used. 3) Coherent pages. The ttm dma pool is used, together with the dma_ttm array os dma_addr_t Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c')
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c379
1 files changed, 362 insertions, 17 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
index 96dc84dc34d0..7776e6f0aef6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
@@ -141,37 +141,374 @@ struct ttm_placement vmw_srf_placement = {
141}; 141};
142 142
143struct vmw_ttm_tt { 143struct vmw_ttm_tt {
144 struct ttm_tt ttm; 144 struct ttm_dma_tt dma_ttm;
145 struct vmw_private *dev_priv; 145 struct vmw_private *dev_priv;
146 int gmr_id; 146 int gmr_id;
147 struct sg_table sgt;
148 struct vmw_sg_table vsgt;
149 uint64_t sg_alloc_size;
150 bool mapped;
147}; 151};
148 152
153/**
154 * Helper functions to advance a struct vmw_piter iterator.
155 *
156 * @viter: Pointer to the iterator.
157 *
158 * These functions return false if past the end of the list,
159 * true otherwise. Functions are selected depending on the current
160 * DMA mapping mode.
161 */
162static bool __vmw_piter_non_sg_next(struct vmw_piter *viter)
163{
164 return ++(viter->i) < viter->num_pages;
165}
166
167static bool __vmw_piter_sg_next(struct vmw_piter *viter)
168{
169 return __sg_page_iter_next(&viter->iter);
170}
171
172
173/**
174 * Helper functions to return a pointer to the current page.
175 *
176 * @viter: Pointer to the iterator
177 *
178 * These functions return a pointer to the page currently
179 * pointed to by @viter. Functions are selected depending on the
180 * current mapping mode.
181 */
182static struct page *__vmw_piter_non_sg_page(struct vmw_piter *viter)
183{
184 return viter->pages[viter->i];
185}
186
187static struct page *__vmw_piter_sg_page(struct vmw_piter *viter)
188{
189 return sg_page_iter_page(&viter->iter);
190}
191
192
193/**
194 * Helper functions to return the DMA address of the current page.
195 *
196 * @viter: Pointer to the iterator
197 *
198 * These functions return the DMA address of the page currently
199 * pointed to by @viter. Functions are selected depending on the
200 * current mapping mode.
201 */
202static dma_addr_t __vmw_piter_phys_addr(struct vmw_piter *viter)
203{
204 return page_to_phys(viter->pages[viter->i]);
205}
206
207static dma_addr_t __vmw_piter_dma_addr(struct vmw_piter *viter)
208{
209 return viter->addrs[viter->i];
210}
211
212static dma_addr_t __vmw_piter_sg_addr(struct vmw_piter *viter)
213{
214 return sg_page_iter_dma_address(&viter->iter);
215}
216
217
218/**
219 * vmw_piter_start - Initialize a struct vmw_piter.
220 *
221 * @viter: Pointer to the iterator to initialize
222 * @vsgt: Pointer to a struct vmw_sg_table to initialize from
223 *
224 * Note that we're following the convention of __sg_page_iter_start, so that
225 * the iterator doesn't point to a valid page after initialization; it has
226 * to be advanced one step first.
227 */
228void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt,
229 unsigned long p_offset)
230{
231 viter->i = p_offset - 1;
232 viter->num_pages = vsgt->num_pages;
233 switch (vsgt->mode) {
234 case vmw_dma_phys:
235 viter->next = &__vmw_piter_non_sg_next;
236 viter->dma_address = &__vmw_piter_phys_addr;
237 viter->page = &__vmw_piter_non_sg_page;
238 viter->pages = vsgt->pages;
239 break;
240 case vmw_dma_alloc_coherent:
241 viter->next = &__vmw_piter_non_sg_next;
242 viter->dma_address = &__vmw_piter_dma_addr;
243 viter->page = &__vmw_piter_non_sg_page;
244 viter->addrs = vsgt->addrs;
245 break;
246 case vmw_dma_map_populate:
247 case vmw_dma_map_bind:
248 viter->next = &__vmw_piter_sg_next;
249 viter->dma_address = &__vmw_piter_sg_addr;
250 viter->page = &__vmw_piter_sg_page;
251 __sg_page_iter_start(&viter->iter, vsgt->sgt->sgl,
252 vsgt->sgt->orig_nents, p_offset);
253 break;
254 default:
255 BUG();
256 }
257}
258
259/**
260 * vmw_ttm_unmap_from_dma - unmap device addresses previsouly mapped for
261 * TTM pages
262 *
263 * @vmw_tt: Pointer to a struct vmw_ttm_backend
264 *
265 * Used to free dma mappings previously mapped by vmw_ttm_map_for_dma.
266 */
267static void vmw_ttm_unmap_from_dma(struct vmw_ttm_tt *vmw_tt)
268{
269 struct device *dev = vmw_tt->dev_priv->dev->dev;
270
271 dma_unmap_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.nents,
272 DMA_BIDIRECTIONAL);
273 vmw_tt->sgt.nents = vmw_tt->sgt.orig_nents;
274}
275
276/**
277 * vmw_ttm_map_for_dma - map TTM pages to get device addresses
278 *
279 * @vmw_tt: Pointer to a struct vmw_ttm_backend
280 *
281 * This function is used to get device addresses from the kernel DMA layer.
282 * However, it's violating the DMA API in that when this operation has been
283 * performed, it's illegal for the CPU to write to the pages without first
284 * unmapping the DMA mappings, or calling dma_sync_sg_for_cpu(). It is
285 * therefore only legal to call this function if we know that the function
286 * dma_sync_sg_for_cpu() is a NOP, and dma_sync_sg_for_device() is at most
287 * a CPU write buffer flush.
288 */
289static int vmw_ttm_map_for_dma(struct vmw_ttm_tt *vmw_tt)
290{
291 struct device *dev = vmw_tt->dev_priv->dev->dev;
292 int ret;
293
294 ret = dma_map_sg(dev, vmw_tt->sgt.sgl, vmw_tt->sgt.orig_nents,
295 DMA_BIDIRECTIONAL);
296 if (unlikely(ret == 0))
297 return -ENOMEM;
298
299 vmw_tt->sgt.nents = ret;
300
301 return 0;
302}
303
304/**
305 * vmw_ttm_map_dma - Make sure TTM pages are visible to the device
306 *
307 * @vmw_tt: Pointer to a struct vmw_ttm_tt
308 *
309 * Select the correct function for and make sure the TTM pages are
310 * visible to the device. Allocate storage for the device mappings.
311 * If a mapping has already been performed, indicated by the storage
312 * pointer being non NULL, the function returns success.
313 */
314static int vmw_ttm_map_dma(struct vmw_ttm_tt *vmw_tt)
315{
316 struct vmw_private *dev_priv = vmw_tt->dev_priv;
317 struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
318 struct vmw_sg_table *vsgt = &vmw_tt->vsgt;
319 struct vmw_piter iter;
320 dma_addr_t old;
321 int ret = 0;
322 static size_t sgl_size;
323 static size_t sgt_size;
324
325 if (vmw_tt->mapped)
326 return 0;
327
328 vsgt->mode = dev_priv->map_mode;
329 vsgt->pages = vmw_tt->dma_ttm.ttm.pages;
330 vsgt->num_pages = vmw_tt->dma_ttm.ttm.num_pages;
331 vsgt->addrs = vmw_tt->dma_ttm.dma_address;
332 vsgt->sgt = &vmw_tt->sgt;
333
334 switch (dev_priv->map_mode) {
335 case vmw_dma_map_bind:
336 case vmw_dma_map_populate:
337 if (unlikely(!sgl_size)) {
338 sgl_size = ttm_round_pot(sizeof(struct scatterlist));
339 sgt_size = ttm_round_pot(sizeof(struct sg_table));
340 }
341 vmw_tt->sg_alloc_size = sgt_size + sgl_size * vsgt->num_pages;
342 ret = ttm_mem_global_alloc(glob, vmw_tt->sg_alloc_size, false,
343 true);
344 if (unlikely(ret != 0))
345 return ret;
346
347 ret = sg_alloc_table_from_pages(&vmw_tt->sgt, vsgt->pages,
348 vsgt->num_pages, 0,
349 (unsigned long)
350 vsgt->num_pages << PAGE_SHIFT,
351 GFP_KERNEL);
352 if (unlikely(ret != 0))
353 goto out_sg_alloc_fail;
354
355 if (vsgt->num_pages > vmw_tt->sgt.nents) {
356 uint64_t over_alloc =
357 sgl_size * (vsgt->num_pages -
358 vmw_tt->sgt.nents);
359
360 ttm_mem_global_free(glob, over_alloc);
361 vmw_tt->sg_alloc_size -= over_alloc;
362 }
363
364 ret = vmw_ttm_map_for_dma(vmw_tt);
365 if (unlikely(ret != 0))
366 goto out_map_fail;
367
368 break;
369 default:
370 break;
371 }
372
373 old = ~((dma_addr_t) 0);
374 vmw_tt->vsgt.num_regions = 0;
375 for (vmw_piter_start(&iter, vsgt, 0); vmw_piter_next(&iter);) {
376 dma_addr_t cur = vmw_piter_dma_addr(&iter);
377
378 if (cur != old + PAGE_SIZE)
379 vmw_tt->vsgt.num_regions++;
380 old = cur;
381 }
382
383 vmw_tt->mapped = true;
384 return 0;
385
386out_map_fail:
387 sg_free_table(vmw_tt->vsgt.sgt);
388 vmw_tt->vsgt.sgt = NULL;
389out_sg_alloc_fail:
390 ttm_mem_global_free(glob, vmw_tt->sg_alloc_size);
391 return ret;
392}
393
394/**
395 * vmw_ttm_unmap_dma - Tear down any TTM page device mappings
396 *
397 * @vmw_tt: Pointer to a struct vmw_ttm_tt
398 *
399 * Tear down any previously set up device DMA mappings and free
400 * any storage space allocated for them. If there are no mappings set up,
401 * this function is a NOP.
402 */
403static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
404{
405 struct vmw_private *dev_priv = vmw_tt->dev_priv;
406
407 if (!vmw_tt->vsgt.sgt)
408 return;
409
410 switch (dev_priv->map_mode) {
411 case vmw_dma_map_bind:
412 case vmw_dma_map_populate:
413 vmw_ttm_unmap_from_dma(vmw_tt);
414 sg_free_table(vmw_tt->vsgt.sgt);
415 vmw_tt->vsgt.sgt = NULL;
416 ttm_mem_global_free(vmw_mem_glob(dev_priv),
417 vmw_tt->sg_alloc_size);
418 break;
419 default:
420 break;
421 }
422 vmw_tt->mapped = false;
423}
424
149static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem) 425static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
150{ 426{
151 struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm); 427 struct vmw_ttm_tt *vmw_be =
428 container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
429 int ret;
430
431 ret = vmw_ttm_map_dma(vmw_be);
432 if (unlikely(ret != 0))
433 return ret;
152 434
153 vmw_be->gmr_id = bo_mem->start; 435 vmw_be->gmr_id = bo_mem->start;
154 436
155 return vmw_gmr_bind(vmw_be->dev_priv, ttm->pages, 437 return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt,
156 ttm->num_pages, vmw_be->gmr_id); 438 ttm->num_pages, vmw_be->gmr_id);
157} 439}
158 440
159static int vmw_ttm_unbind(struct ttm_tt *ttm) 441static int vmw_ttm_unbind(struct ttm_tt *ttm)
160{ 442{
161 struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm); 443 struct vmw_ttm_tt *vmw_be =
444 container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
162 445
163 vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id); 446 vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
447
448 if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind)
449 vmw_ttm_unmap_dma(vmw_be);
450
164 return 0; 451 return 0;
165} 452}
166 453
167static void vmw_ttm_destroy(struct ttm_tt *ttm) 454static void vmw_ttm_destroy(struct ttm_tt *ttm)
168{ 455{
169 struct vmw_ttm_tt *vmw_be = container_of(ttm, struct vmw_ttm_tt, ttm); 456 struct vmw_ttm_tt *vmw_be =
170 457 container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
171 ttm_tt_fini(ttm); 458
459 vmw_ttm_unmap_dma(vmw_be);
460 if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
461 ttm_dma_tt_fini(&vmw_be->dma_ttm);
462 else
463 ttm_tt_fini(ttm);
172 kfree(vmw_be); 464 kfree(vmw_be);
173} 465}
174 466
467static int vmw_ttm_populate(struct ttm_tt *ttm)
468{
469 struct vmw_ttm_tt *vmw_tt =
470 container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
471 struct vmw_private *dev_priv = vmw_tt->dev_priv;
472 struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
473 int ret;
474
475 if (ttm->state != tt_unpopulated)
476 return 0;
477
478 if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
479 size_t size =
480 ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t));
481 ret = ttm_mem_global_alloc(glob, size, false, true);
482 if (unlikely(ret != 0))
483 return ret;
484
485 ret = ttm_dma_populate(&vmw_tt->dma_ttm, dev_priv->dev->dev);
486 if (unlikely(ret != 0))
487 ttm_mem_global_free(glob, size);
488 } else
489 ret = ttm_pool_populate(ttm);
490
491 return ret;
492}
493
494static void vmw_ttm_unpopulate(struct ttm_tt *ttm)
495{
496 struct vmw_ttm_tt *vmw_tt = container_of(ttm, struct vmw_ttm_tt,
497 dma_ttm.ttm);
498 struct vmw_private *dev_priv = vmw_tt->dev_priv;
499 struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
500
501 vmw_ttm_unmap_dma(vmw_tt);
502 if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
503 size_t size =
504 ttm_round_pot(ttm->num_pages * sizeof(dma_addr_t));
505
506 ttm_dma_unpopulate(&vmw_tt->dma_ttm, dev_priv->dev->dev);
507 ttm_mem_global_free(glob, size);
508 } else
509 ttm_pool_unpopulate(ttm);
510}
511
175static struct ttm_backend_func vmw_ttm_func = { 512static struct ttm_backend_func vmw_ttm_func = {
176 .bind = vmw_ttm_bind, 513 .bind = vmw_ttm_bind,
177 .unbind = vmw_ttm_unbind, 514 .unbind = vmw_ttm_unbind,
@@ -183,20 +520,28 @@ struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev,
183 struct page *dummy_read_page) 520 struct page *dummy_read_page)
184{ 521{
185 struct vmw_ttm_tt *vmw_be; 522 struct vmw_ttm_tt *vmw_be;
523 int ret;
186 524
187 vmw_be = kmalloc(sizeof(*vmw_be), GFP_KERNEL); 525 vmw_be = kzalloc(sizeof(*vmw_be), GFP_KERNEL);
188 if (!vmw_be) 526 if (!vmw_be)
189 return NULL; 527 return NULL;
190 528
191 vmw_be->ttm.func = &vmw_ttm_func; 529 vmw_be->dma_ttm.ttm.func = &vmw_ttm_func;
192 vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev); 530 vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);
193 531
194 if (ttm_tt_init(&vmw_be->ttm, bdev, size, page_flags, dummy_read_page)) { 532 if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
195 kfree(vmw_be); 533 ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags,
196 return NULL; 534 dummy_read_page);
197 } 535 else
198 536 ret = ttm_tt_init(&vmw_be->dma_ttm.ttm, bdev, size, page_flags,
199 return &vmw_be->ttm; 537 dummy_read_page);
538 if (unlikely(ret != 0))
539 goto out_no_init;
540
541 return &vmw_be->dma_ttm.ttm;
542out_no_init:
543 kfree(vmw_be);
544 return NULL;
200} 545}
201 546
202int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags) 547int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
@@ -332,8 +677,8 @@ static int vmw_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible)
332 677
333struct ttm_bo_driver vmw_bo_driver = { 678struct ttm_bo_driver vmw_bo_driver = {
334 .ttm_tt_create = &vmw_ttm_tt_create, 679 .ttm_tt_create = &vmw_ttm_tt_create,
335 .ttm_tt_populate = &ttm_pool_populate, 680 .ttm_tt_populate = &vmw_ttm_populate,
336 .ttm_tt_unpopulate = &ttm_pool_unpopulate, 681 .ttm_tt_unpopulate = &vmw_ttm_unpopulate,
337 .invalidate_caches = vmw_invalidate_caches, 682 .invalidate_caches = vmw_invalidate_caches,
338 .init_mem_type = vmw_init_mem_type, 683 .init_mem_type = vmw_init_mem_type,
339 .evict_flags = vmw_evict_flags, 684 .evict_flags = vmw_evict_flags,