diff options
author | Dave Airlie <airlied@redhat.com> | 2011-12-21 11:30:31 +0000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-12-21 17:18:25 +0000 |
commit | 9f877b95d836ffbec66d5db7e2359d748900a998 (patch) | |
tree | 412de50d42b9bd7126cd67da0c3ac51355ca17af | |
parent | 91d3c9674804f33b25979b2efd6cdcceaafa1f42 (diff) |
nouveau: add prime support.drm-prime-dmabuf
this involves changing the nouveau_bo_new api.
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bo.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_channel.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_prime.c | 189 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_crtc.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_crtc.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_evo.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvd0_display.c | 4 |
14 files changed, 235 insertions, 16 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index 35ef5b1e3566..f189ae6cb7b2 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -33,7 +33,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv50_calc.o \ nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \ nv50_vram.o nvc0_vram.o \ - nv50_vm.o nvc0_vm.o + nv50_vm.o nvc0_vm.o nouveau_prime.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index cc3f12db8e07..c16cb27f2ffb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -88,11 +88,16 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags, int nouveau_bo_new(struct drm_device *dev, int size, int align, uint32_t flags, uint32_t tile_mode, uint32_t tile_flags, + struct sg_table *sg, struct nouveau_bo **pnvbo) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_bo *nvbo; int ret; + int type = ttm_bo_type_device; + + if (sg) + type = ttm_bo_type_sg; nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); if (!nvbo) @@ -115,8 +120,9 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, nouveau_bo_placement_set(nvbo, flags, 0); ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size, - ttm_bo_type_device, &nvbo->placement, - align >> PAGE_SHIFT, 0, false, NULL, size, NULL, + type, &nvbo->placement, + align >> PAGE_SHIFT, 0, false, NULL, size, + sg, nouveau_bo_del_ttm); if (ret) { /* ttm will call nouveau_bo_del_ttm if it fails.. */ diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index bb6ec9ef8676..189ba12eeccf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -38,7 +38,7 @@ nouveau_channel_pushbuf_init(struct nouveau_channel *chan) int ret; /* allocate buffer object */ - ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, &chan->pushbuf_bo); + ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, NULL, &chan->pushbuf_bo); if (ret) goto out; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 9791d13c9e3b..7d19dd043186 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -392,7 +392,7 @@ static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | - DRIVER_MODESET, + DRIVER_MODESET | DRIVER_PRIME, .load = nouveau_load, .firstopen = nouveau_firstopen, .lastclose = nouveau_lastclose, @@ -428,6 +428,9 @@ static struct drm_driver driver = { .llseek = noop_llseek, }, + .prime_handle_to_fd = nouveau_gem_prime_handle_to_fd, + .prime_fd_to_handle = nouveau_gem_prime_fd_to_handle, + .gem_init_object = nouveau_gem_object_new, .gem_free_object = nouveau_gem_object_del, .gem_open_object = nouveau_gem_object_open, diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 106f31fb0571..3931ea7ae0f4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -49,6 +49,7 @@ struct nouveau_fpriv { spinlock_t lock; struct list_head channels; struct nouveau_vm *vm; + struct drm_prime_file_private prime; }; static inline struct nouveau_fpriv * @@ -1328,7 +1329,9 @@ extern int nv04_crtc_create(struct drm_device *, int index); extern struct ttm_bo_driver nouveau_bo_driver; extern int nouveau_bo_new(struct drm_device *, int size, int align, uint32_t flags, uint32_t tile_mode, - uint32_t tile_flags, struct nouveau_bo **); + uint32_t tile_flags, + struct sg_table *sg, + struct nouveau_bo **); extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags); extern int nouveau_bo_unpin(struct nouveau_bo *); extern int nouveau_bo_map(struct nouveau_bo *); @@ -1413,6 +1416,13 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, extern int nouveau_gem_ioctl_info(struct drm_device *, void *, struct drm_file *); +extern int nouveau_gem_prime_handle_to_fd(struct drm_device *dev, + struct drm_file *file_priv, + uint32_t handle, int *prime_fd); +extern int nouveau_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, + int prime_fd, uint32_t *handle_p); + /* nouveau_display.c */ int nouveau_vblank_enable(struct drm_device *dev, int crtc); void nouveau_vblank_disable(struct drm_device *dev, int crtc); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 2f6daae68b9d..71c7a4eacfaa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -574,7 +574,7 @@ nouveau_fence_init(struct drm_device *dev) /* Create a shared VRAM heap for cross-channel sync. */ if (USE_SEMA(dev)) { ret = nouveau_bo_new(dev, size, 0, TTM_PL_FLAG_VRAM, - 0, 0, &dev_priv->fence.bo); + 0, 0, NULL, &dev_priv->fence.bo); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 5f0bc57fdaab..c330ad8d6c44 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -23,6 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ +#include <linux/dma-buf.h> #include "drmP.h" #include "drm.h" @@ -53,6 +54,10 @@ nouveau_gem_object_del(struct drm_gem_object *gem) nouveau_bo_unpin(nvbo); } + if (gem->import_attach) { + drm_prime_gem_destroy(gem, nvbo->bo.sg); + } + ttm_bo_unref(&bo); drm_gem_object_release(gem); @@ -104,6 +109,9 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) struct nouveau_vma *vma; int ret; + if (gem->import_attach) + drm_prime_remove_fd_handle_mapping(&fpriv->prime, gem->import_attach->dmabuf); + if (!fpriv->vm) return; @@ -119,6 +127,7 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) } } ttm_bo_unreserve(&nvbo->bo); + } int @@ -139,7 +148,7 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain, flags |= TTM_PL_FLAG_SYSTEM; ret = nouveau_bo_new(dev, size, align, flags, tile_mode, - tile_flags, pnvbo); + tile_flags, NULL, pnvbo); if (ret) return ret; nvbo = *pnvbo; diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 36bec4807701..2411871bab54 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -446,7 +446,7 @@ nouveau_mem_vram_init(struct drm_device *dev) if (dev_priv->card_type < NV_50) { ret = nouveau_bo_new(dev, 256*1024, 0, TTM_PL_FLAG_VRAM, - 0, 0, &dev_priv->vga_ram); + 0, 0, NULL, &dev_priv->vga_ram); if (ret == 0) ret = nouveau_bo_pin(dev_priv->vga_ram, TTM_PL_FLAG_VRAM); diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c new file mode 100644 index 000000000000..020820a127c8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_prime.c @@ -0,0 +1,189 @@ + +#include "drmP.h" +#include "drm.h" + +#include "nouveau_drv.h" +#include "nouveau_drm.h" +#include "nouveau_dma.h" + +#include <linux/dma-buf.h> + +static struct sg_table *nouveau_gem_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction dir) +{ + struct nouveau_bo *nvbo = attachment->dmabuf->priv; + struct drm_device *dev = nvbo->gem->dev; + int npages = nvbo->bo.num_pages; + struct sg_table *sg; + + mutex_lock(&dev->struct_mutex); + sg = drm_prime_pages_to_sg(nvbo->bo.ttm->pages, npages); + mutex_unlock(&dev->struct_mutex); + return sg; +} + +static void nouveau_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *sg) +{ + sg_free_table(sg); + kfree(sg); +} + +static void nouveau_gem_dmabuf_release(struct dma_buf *dma_buf) +{ + struct nouveau_bo *nvbo = dma_buf->priv; + + if (nvbo->gem->export_dma_buf == dma_buf) { + DRM_ERROR("unreference dmabuf %p\n", nvbo->gem); + nvbo->gem->prime_fd = -1; + nvbo->gem->export_dma_buf = NULL; + drm_gem_object_unreference_unlocked(nvbo->gem); + } +} + +struct dma_buf_ops nouveau_dmabuf_ops = { + .map_dma_buf = nouveau_gem_map_dma_buf, + .unmap_dma_buf = nouveau_gem_unmap_dma_buf, + .release = nouveau_gem_dmabuf_release, +}; + +static int +nouveau_prime_new(struct drm_device *dev, + size_t size, + struct sg_table *sg, + struct nouveau_bo **pnvbo) +{ + struct nouveau_bo *nvbo; + u32 flags = 0; + int ret; + + flags = TTM_PL_FLAG_TT; + + ret = nouveau_bo_new(dev, size, 0, flags, 0, 0, + sg, pnvbo); + if (ret) + return ret; + nvbo = *pnvbo; + + /* we restrict allowed domains on nv50+ to only the types + * that were requested at creation time. not possibly on + * earlier chips without busting the ABI. + */ + nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART; + nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size); + if (!nvbo->gem) { + nouveau_bo_ref(NULL, pnvbo); + return -ENOMEM; + } + +// nvbo->bo.persistant_swap_storage = nvbo->gem->filp; + nvbo->gem->driver_private = nvbo; + return 0; +} + +int nouveau_gem_prime_handle_to_fd(struct drm_device *dev, + struct drm_file *file_priv, + uint32_t handle, int *prime_fd) +{ + struct nouveau_bo *nvbo; + struct drm_gem_object *gem; + int ret = 0; + + gem = drm_gem_object_lookup(dev, file_priv, handle); + if (!gem) + return -ENOENT; + nvbo = nouveau_gem_object(gem); + + if (gem->prime_fd != -1) { + /* drop lookup reference here already one on the fd */ + drm_gem_object_unreference_unlocked(gem); + goto have_fd; + } + + /* pin buffer into GTT */ + ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT); + if (ret) { + ret = -EINVAL; + goto out_unlock; + } + + gem->export_dma_buf = dma_buf_export(nvbo, &nouveau_dmabuf_ops, gem->size, 0600); + if (IS_ERR(gem->export_dma_buf)) { + ret = PTR_ERR(gem->export_dma_buf); + goto out_unlock; + } + gem->prime_fd = dma_buf_fd(gem->export_dma_buf); + + /* don't drop reference since fd doesn't have it */ +have_fd: + *prime_fd = gem->prime_fd; + return ret; +out_unlock: + drm_gem_object_unreference_unlocked(gem); + return ret; +} + +int nouveau_gem_prime_fd_to_handle(struct drm_device *dev, + struct drm_file *file_priv, + int prime_fd, uint32_t *handle_p) +{ + struct nouveau_fpriv *fpriv = file_priv->driver_priv; + struct dma_buf *dma_buf; + struct dma_buf_attachment *attach; + struct sg_table *sg; + struct nouveau_bo *nvbo; + int ret; + uint32_t handle; + + dma_buf = dma_buf_get(prime_fd); + if (IS_ERR(dma_buf)) + return PTR_ERR(dma_buf); + + ret = drm_prime_lookup_fd_handle_mapping(&fpriv->prime, dma_buf, &handle); + if (!ret) { + dma_buf_put(dma_buf); + *handle_p = handle; + return 0; + } + + /* need to attach */ + attach = dma_buf_attach(dma_buf, dev->dev); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + goto fail_put; + } + + sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR(sg)) { + ret = PTR_ERR(sg); + goto fail_detach; + } + + ret = nouveau_prime_new(dev, dma_buf->size, sg, &nvbo); + if (ret) + goto fail_unmap; + + nvbo->gem->import_attach = attach; + ret = drm_gem_handle_create(file_priv, nvbo->gem, &handle); + drm_gem_object_unreference_unlocked(nvbo->gem); + if (ret) + goto fail_unmap; + + ret = drm_prime_insert_fd_handle_mapping(&fpriv->prime, dma_buf, handle); + if (ret) + goto fail_handle; + + *handle_p = handle; + return 0; + +fail_handle: + drm_gem_object_handle_unreference_unlocked(nvbo->gem); +fail_unmap: + dma_buf_unmap_attachment(attach, sg); +fail_detach: + dma_buf_detach(dma_buf, attach); +fail_put: + dma_buf_put(dma_buf); + return ret; +} + diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 364b61198a32..45cc580ce7ad 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -884,6 +884,7 @@ nouveau_open(struct drm_device *dev, struct drm_file *file_priv) spin_lock_init(&fpriv->lock); INIT_LIST_HEAD(&fpriv->channels); + drm_prime_init_file_private(&fpriv->prime); if (dev_priv->card_type == NV_50) { ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL, @@ -917,6 +918,7 @@ void nouveau_postclose(struct drm_device *dev, struct drm_file *file_priv) { struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); + drm_prime_destroy_file_private(&fpriv->prime); nouveau_vm_ref(NULL, &fpriv->vm, NULL); kfree(fpriv); } diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index 5e45398a9e2d..c3ff3a7d7a9d 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -1047,7 +1047,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num) drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, &nv_crtc->cursor.nvbo); + 0, 0x0000, NULL, &nv_crtc->cursor.nvbo); if (!ret) { ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 882080e0b4f5..03aa6f10ff27 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -754,7 +754,7 @@ nv50_crtc_create(struct drm_device *dev, int index) nv_crtc->lut.depth = 0; ret = nouveau_bo_new(dev, 4096, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, &nv_crtc->lut.nvbo); + 0, 0x0000, NULL, &nv_crtc->lut.nvbo); if (!ret) { ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); if (!ret) @@ -780,7 +780,7 @@ nv50_crtc_create(struct drm_device *dev, int index) drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, &nv_crtc->cursor.nvbo); + 0, 0x0000, NULL, &nv_crtc->cursor.nvbo); if (!ret) { ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index c99d9751880c..faf9b9a025f4 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -117,7 +117,7 @@ nv50_evo_channel_new(struct drm_device *dev, int chid, evo->user_get = 4; evo->user_put = 0; - ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, + ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, NULL, &evo->pushbuf_bo); if (ret == 0) ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM); @@ -333,7 +333,7 @@ nv50_evo_create(struct drm_device *dev) goto err; ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, - 0, 0x0000, &dispc->sem.bo); + 0, 0x0000, NULL, &dispc->sem.bo); if (!ret) { ret = nouveau_bo_pin(dispc->sem.bo, TTM_PL_FLAG_VRAM); if (!ret) diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index cb006a718e70..3e5e9497746d 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -565,7 +565,7 @@ nvd0_crtc_create(struct drm_device *dev, int index) drm_mode_crtc_set_gamma_size(crtc, 256); ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, &nv_crtc->cursor.nvbo); + 0, 0x0000, NULL, &nv_crtc->cursor.nvbo); if (!ret) { ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) @@ -578,7 +578,7 @@ nvd0_crtc_create(struct drm_device *dev, int index) goto out; ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, &nv_crtc->lut.nvbo); + 0, 0x0000, NULL, &nv_crtc->lut.nvbo); if (!ret) { ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); if (!ret) |