gfx: imgv: add support for wrapping a pvr buffer as ttm buffer
authorImre Deak <imre.deak@intel.com>
Thu, 22 Dec 2011 20:48:33 +0000 (22:48 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 3 Jul 2012 09:29:20 +0000 (12:29 +0300)
Signed-off-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Pauli Nieminen <pauli.nieminen@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
drivers/staging/mrst/drv/psb_drv.c
drivers/staging/mrst/drv/psb_drv.h
drivers/staging/mrst/imgv/psb_ttm_glue.c
drivers/staging/mrst/imgv/psb_ttm_placement_user.c
drivers/staging/mrst/imgv/psb_ttm_placement_user.h
drivers/staging/mrst/imgv/psb_ttm_userobj_api.h

index 8e1148b..e5a2d0e 100644 (file)
@@ -254,6 +254,8 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 #define DRM_PSB_TTM_PL_WAITIDLE  (TTM_PL_WAITIDLE + DRM_PSB_PLACEMENT_OFFSET)
 #define DRM_PSB_TTM_PL_SETSTATUS (TTM_PL_SETSTATUS + DRM_PSB_PLACEMENT_OFFSET)
 #define DRM_PSB_TTM_PL_CREATE_UB (TTM_PL_CREATE_UB + DRM_PSB_PLACEMENT_OFFSET)
+#define DRM_PSB_TTM_PL_WRAP_PVR_BUF   \
+                               (TTM_PL_WRAP_PVR_BUF + DRM_PSB_PLACEMENT_OFFSET)
 
 /*
  * TTM fence extension.
@@ -313,6 +315,10 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
         DRM_IOWR(DRM_COMMAND_BASE + DRM_BUFFER_CLASS_VIDEO, \
              BC_Video_ioctl_package)
 
+#define DRM_IOCTL_PSB_TTM_PL_WRAP_PVR_BUF \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_PSB_TTM_PL_WRAP_PVR_BUF, \
+                union ttm_pl_create_arg)
+
 static int psb_vt_leave_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
 static int psb_vt_enter_ioctl(struct drm_device *dev, void *data,
@@ -425,6 +431,8 @@ static struct drm_ioctl_desc psb_ioctls[] = {
        DRM_AUTH),
        PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_CREATE_UB, psb_pl_ub_create_ioctl,
        DRM_AUTH),
+       PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_PL_WRAP_PVR_BUF,
+                     psb_pl_wrap_pvr_buf_ioctl, DRM_AUTH),
        PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_FENCE_SIGNALED,
        psb_fence_signaled_ioctl, DRM_AUTH),
        PSB_IOCTL_DEF(DRM_IOCTL_PSB_TTM_FENCE_FINISH, psb_fence_finish_ioctl,
index 1e81657..2d45c06 100644 (file)
@@ -1037,6 +1037,8 @@ extern int psb_pl_create_ioctl(struct drm_device *dev, void *data,
                               struct drm_file *file_priv);
 extern int psb_pl_ub_create_ioctl(struct drm_device *dev, void *data,
                               struct drm_file *file_priv);
+extern int psb_pl_wrap_pvr_buf_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv);
 extern int psb_extension_ioctl(struct drm_device *dev, void *data,
                               struct drm_file *file_priv);
 extern int psb_ttm_global_init(struct drm_psb_private *dev_priv);
index d2010eb..af5abfd 100644 (file)
@@ -198,6 +198,16 @@ int psb_pl_ub_create_ioctl(struct drm_device *dev, void *data,
                                      &dev_priv->bdev, &dev_priv->ttm_lock, data);
 
 }
+
+int psb_pl_wrap_pvr_buf_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct drm_psb_private *dev_priv = psb_priv(dev);
+
+       return ttm_pl_wrap_pvr_buf_ioctl(psb_fpriv(file_priv)->tfile,
+                                   &dev_priv->bdev, &dev_priv->ttm_lock, data);
+}
+
 /**
  * psb_ttm_fault - Wrapper around the ttm fault method.
  *
index f766b31..903b0fe 100644 (file)
@@ -26,6 +26,8 @@
 #include "ttm/ttm_object.h"
 #include "psb_ttm_userobj_api.h"
 #include "ttm/ttm_lock.h"
+#include "psb_drm.h"
+#include "pvr_bridge_km.h"
 #include <linux/slab.h>
 #include <linux/sched.h>
 
@@ -46,6 +48,17 @@ static uint32_t psb_busy_prios[] = {
 
 static const struct ttm_placement default_placement = {0, 0, 0, NULL, 5, psb_busy_prios};
 
+static uint32_t psb_pvr_busy_prios[] = {
+       TTM_PL_TT,
+       TTM_PL_PRIV1, /* DRM_PSB_MEM_MMU */
+       TTM_PL_SYSTEM
+};
+
+static const struct ttm_placement pvr_default_placement = {
+       .busy_placement         = psb_pvr_busy_prios,
+       .num_busy_placement     = ARRAY_SIZE(psb_pvr_busy_prios),
+};
+
 static size_t ttm_pl_size(struct ttm_bo_device *bdev, unsigned long num_pages)
 {
        size_t page_array_size =
@@ -197,6 +210,18 @@ static int ttm_bo_create_private(struct ttm_bo_device *bdev,
        return ret;
 }
 
+static bool fixed_placement_valid(uint32_t pl_flags)
+{
+       if (!(pl_flags & TTM_PL_FLAG_NO_SWAP))
+               return false;
+
+       pl_flags &= TTM_PL_MASK_MEM;
+       pl_flags &= ~(DRM_PSB_FLAG_MEM_MMU | TTM_PL_FLAG_TT |
+                     TTM_PL_FLAG_SYSTEM);
+
+       return !pl_flags;
+}
+
 static uint32_t normalize_placement_flags(uint32_t flags)
 {
        if ((flags & TTM_PL_MASK_CACHING) == 0)
@@ -213,10 +238,17 @@ static int set_clear_placement_flags(struct ttm_buffer_object *bo, uint32_t set,
        uint32_t cur = bo->mem.placement;
        uint32_t new;
        bool is_root;
+       bool has_fixed_pages;
+       char *flag_name = "no swap";
 
        new = (cur | set) & ~clear;
        new = normalize_placement_flags(new);
 
+       has_fixed_pages = drm_psb_has_fixed_pages(bo->ttm->be);
+       if (has_fixed_pages && !fixed_placement_valid(new))
+               goto err;
+
+       flag_name = "no evict";
        is_root = capable(CAP_SYS_ADMIN);
        if (!is_root && (cur ^ new) & TTM_PL_FLAG_NO_EVICT)
                goto err;
@@ -225,9 +257,9 @@ static int set_clear_placement_flags(struct ttm_buffer_object *bo, uint32_t set,
 
        return 0;
 err:
-       pr_debug("imgv: Permission denied to set 'no evict' flag: "
+       pr_debug("imgv: Permission denied to set '%s' flag: "
                 "is_root %d cur %08x set %08x clear %08x\n",
-                is_root, cur, set, clear);
+                flag_name, is_root, cur, set, clear);
 
        return -EACCES;
 }
@@ -270,6 +302,7 @@ struct create_params {
        size_t size;
        off_t align;
        unsigned long user_address;
+       struct page **pages;
        struct ttm_placement *placement;
        struct ttm_object_file *tfile;
        bool shareable;
@@ -307,14 +340,24 @@ static int pl_create_buf(struct create_params *p, struct ttm_lock *lock,
        ret = ttm_bo_init(p->bdev, bo, pg_cnt << PAGE_SHIFT, p->bo_type,
                          p->placement, p->align, p->user_address, true, NULL,
                          acc_size, &ttm_bo_user_destroy);
-       ttm_read_unlock(lock);
 
        /*
         * Note that the ttm_buffer_object_init function
         * would've called the destroy function on failure!!
         */
-       if (ret < 0)
+       if (ret < 0) {
+               ttm_read_unlock(lock);
                goto err2;
+       }
+
+       if (p->pages)
+               drm_psb_set_fixed_pages(bo->ttm, p->pages, pg_cnt);
+
+       ttm_read_unlock(lock);
+
+       /* ttm_bo_unref->destroy will unset the fixed pages on failure */
+       if (ret < 0)
+               goto err3;
 
        tmp = ttm_bo_reference(bo);
 
@@ -348,22 +391,20 @@ int ttm_pl_create_ioctl(struct ttm_object_file *tfile,
        union ttm_pl_create_arg *arg = data;
        struct ttm_pl_create_req *req = &arg->req;
        struct ttm_pl_rep *rep = &arg->rep;
-       struct ttm_placement pl;
-       uint32_t pl_flags;
+       struct ttm_placement pl = default_placement;
+       uint32_t pl_flags = normalize_placement_flags(req->placement);
        struct create_params cp = {
                .bdev           = bdev,
                .bo_type        = ttm_bo_type_device,
                .size           = req->size,
                .align          = req->page_alignment,
+               .placement      = &pl,
                .tfile          = tfile,
                .shareable      = req->placement & TTM_PL_FLAG_SHARED,
        };
 
-       pl_flags = normalize_placement_flags(req->placement);
-       pl = default_placement;
        pl.num_placement = 1;
        pl.placement = &pl_flags;
-       cp.placement = &pl;
 
        return pl_create_buf(&cp, lock, rep);
 }
@@ -376,26 +417,70 @@ int ttm_pl_ub_create_ioctl(struct ttm_object_file *tfile,
        struct ttm_pl_create_ub_req *req = &arg->req;
        struct ttm_pl_rep *rep = &arg->rep;
        struct ttm_placement pl = default_placement;
-       uint32_t pl_flags;
+       uint32_t pl_flags = normalize_placement_flags(req->placement);
        struct create_params cp = {
                .bdev           = bdev,
                .bo_type        = ttm_bo_type_user,
                .size           = req->size,
                .user_address   = req->user_address,
                .align          = req->page_alignment,
+               .placement      = &pl,
                .tfile          = tfile,
                .shareable      = req->placement & TTM_PL_FLAG_SHARED,
        };
 
-       pl_flags = normalize_placement_flags(req->placement);
-       pl = default_placement;
        pl.num_placement = 1;
        pl.placement = &pl_flags;
-       cp.placement = &pl;
 
        return pl_create_buf(&cp, lock, rep);
 }
 
+int ttm_pl_wrap_pvr_buf_ioctl(struct ttm_object_file *tfile,
+                       struct ttm_bo_device *bdev,
+                       struct ttm_lock *lock, void *data)
+{
+       union ttm_pl_wrap_pvr_buf_arg *arg = data;
+       struct ttm_pl_wrap_pvr_buf_req *req = &arg->req;
+       struct ttm_pl_rep *rep = &arg->rep;
+       struct ttm_placement pl = pvr_default_placement;
+       struct pvr_buf_info buf_info;
+       uint32_t pl_flags = normalize_placement_flags(req->placement);
+       int ret;
+       struct create_params cp = {
+               .bdev           = bdev,
+               .bo_type        = ttm_bo_type_device,
+               .align          = req->page_alignment,
+               .placement      = &pl,
+               .tfile          = tfile,
+               .shareable      = req->placement & TTM_PL_FLAG_SHARED,
+       };
+
+       if (!fixed_placement_valid(pl_flags))
+               return -EINVAL;
+
+       pl.num_placement = 1;
+       pl.placement = &pl_flags;
+
+       ret = pvr_lookup_dev_buf(req->handle, &buf_info);
+       if (ret < 0)
+               return ret;
+       /*
+        * We set here the ttm pages to point to the fixed pages from the
+        * pvr buffer. Due to TTM_PL_FLAG_NO_SWAP set above and the
+        * busy_placement settings, these will never be swapped or moved to
+        * an IO region and thus never be freed before the buffer itself is
+        * destroyed.
+        */
+       cp.pages = buf_info.pages;
+       cp.size = buf_info.page_cnt;
+
+       ret = pl_create_buf(&cp, lock, rep);
+
+       pvr_put_dev_buf(&buf_info);
+
+       return ret;
+}
+
 int ttm_pl_reference_ioctl(struct ttm_object_file *tfile, void *data)
 {
        union ttm_pl_reference_arg *arg = data;
index 8b7068b..84c1e79 100644 (file)
@@ -78,6 +78,21 @@ struct ttm_pl_create_ub_req {
 };
 
 /**
+ * struct ttm_pl_wrap_pvr_buf_req
+ *
+ * @handle: PVR buffer id
+ * @placement: Flags that indicate initial acceptable
+ *  placement.
+ *
+ * Input to the TTM_WRAP_PVR_BUF ioctl.
+ */
+struct ttm_pl_wrap_pvr_buf_req {
+       uint32_t handle;
+       uint32_t placement;
+       uint32_t page_alignment;
+};
+
+/**
  * struct ttm_pl_rep
  *
  * @gpu_offset: The current offset into the memory region used.
@@ -237,6 +252,11 @@ union ttm_pl_create_ub_arg {
        struct ttm_pl_rep rep;
 };
 
+union ttm_pl_wrap_pvr_buf_arg {
+       struct ttm_pl_wrap_pvr_buf_req req;
+       struct ttm_pl_rep rep;
+};
+
 /*
  * Ioctl offsets.
  */
@@ -248,5 +268,6 @@ union ttm_pl_create_ub_arg {
 #define TTM_PL_WAITIDLE    0x04
 #define TTM_PL_SETSTATUS   0x05
 #define TTM_PL_CREATE_UB   0x06
+#define TTM_PL_WRAP_PVR_BUF     0x07
 
 #endif
index 032bcfe..468784c 100644 (file)
@@ -44,6 +44,9 @@ extern int ttm_pl_create_ioctl(struct ttm_object_file *tfile,
 extern int ttm_pl_ub_create_ioctl(struct ttm_object_file *tfile,
                                  struct ttm_bo_device *bdev,
                                  struct ttm_lock *lock, void *data);
+extern int ttm_pl_wrap_pvr_buf_ioctl(struct ttm_object_file *tfile,
+                               struct ttm_bo_device *bdev,
+                               struct ttm_lock *lock, void *data);
 extern int ttm_pl_reference_ioctl(struct ttm_object_file *tfile, void *data);
 extern int ttm_pl_unref_ioctl(struct ttm_object_file *tfile, void *data);
 extern int ttm_pl_synccpu_ioctl(struct ttm_object_file *tfile, void *data);