summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandeep Panda <spanda@codeaurora.org>2016-10-24 09:48:50 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2016-11-14 08:42:12 -0800
commit7124a4ae4976215f4a0906e92099d149c3e36a6d (patch)
tree02533ad7a60852d94d363a27ca76c0e6d2daee3d
parentbcc085a8facb1e3e32460298668d5d76c503ebd8 (diff)
drm/msm: create separate commit thread for each display
This change creates separate threads for commit on each display, so that one display commit is not blocked on other display's commit. Hence improving performance in multi display use cases. Change-Id: Ibd0dae1da53ec3a72de8b96c3c03ce51830cb4f9 Signed-off-by: Sandeep Panda <spanda@codeaurora.org>
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c65
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c43
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h13
3 files changed, 114 insertions, 7 deletions
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index bd58e0bbbad7..d8791155236c 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -26,6 +26,7 @@ struct msm_commit {
uint32_t fence;
struct msm_fence_cb fence_cb;
uint32_t crtc_mask;
+ struct kthread_work commit_work;
};
/* block until specified crtcs are no longer pending update, and
@@ -435,6 +436,20 @@ static void fence_cb(struct msm_fence_cb *cb)
complete_commit(commit);
}
+static void _msm_drm_commit_work_cb(struct kthread_work *work)
+{
+ struct msm_commit *commit = NULL;
+
+ if (!work) {
+ DRM_ERROR("%s: Invalid commit work data!\n", __func__);
+ return;
+ }
+
+ commit = container_of(work, struct msm_commit, commit_work);
+
+ complete_commit(commit);
+}
+
static struct msm_commit *commit_init(struct drm_atomic_state *state)
{
struct msm_commit *commit = kzalloc(sizeof(*commit), GFP_KERNEL);
@@ -452,6 +467,7 @@ static struct msm_commit *commit_init(struct drm_atomic_state *state)
* bo's..
*/
INIT_FENCE_CB(&commit->fence_cb, fence_cb);
+ init_kthread_work(&commit->commit_work, _msm_drm_commit_work_cb);
return commit;
}
@@ -464,6 +480,47 @@ static void commit_set_fence(struct msm_commit *commit,
msm_gem_fence(to_msm_bo(obj), MSM_PREP_READ));
}
+/* Start display thread function */
+static int msm_atomic_commit_dispatch(struct drm_device *dev,
+ struct drm_atomic_state *state, struct msm_commit *commit)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_crtc *crtc = NULL;
+ struct drm_crtc_state *crtc_state = NULL;
+ int ret = -EINVAL, i = 0, j = 0;
+
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ for (j = 0; j < priv->num_crtcs; j++) {
+ if (priv->disp_thread[j].crtc_id ==
+ crtc->base.id) {
+ if (priv->disp_thread[j].thread) {
+ queue_kthread_work(
+ &priv->disp_thread[j].worker,
+ &commit->commit_work);
+ /* only return zero if work is
+ * queued successfully.
+ */
+ ret = 0;
+ } else {
+ DRM_ERROR(" Error for crtc_id: %d\n",
+ priv->disp_thread[j].crtc_id);
+ }
+ break;
+ }
+ }
+ /*
+ * TODO: handle cases where there will be more than
+ * one crtc per commit cycle. Remove this check then.
+ * Current assumption is there will be only one crtc
+ * per commit cycle.
+ */
+ if (j < priv->num_crtcs)
+ break;
+ }
+
+ return ret;
+}
+
/**
* drm_atomic_helper_commit - commit validated state object
* @dev: DRM device
@@ -567,7 +624,13 @@ int msm_atomic_commit(struct drm_device *dev,
*/
if (async) {
- msm_queue_fence_cb(dev, &commit->fence_cb, commit->fence);
+ ret = msm_atomic_commit_dispatch(dev, state, commit);
+ if (ret) {
+ DRM_ERROR("%s: atomic commit failed\n", __func__);
+ drm_atomic_state_free(state);
+ commit_destroy(commit);
+ goto error;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 46b1f007648e..014d4715f3f6 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -124,7 +124,7 @@ struct vblank_event {
bool enable;
};
-static void vblank_ctrl_worker(struct work_struct *work)
+static void vblank_ctrl_worker(struct kthread_work *work)
{
struct msm_vblank_ctrl *vbl_ctrl = container_of(work,
struct msm_vblank_ctrl, work);
@@ -172,7 +172,7 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv,
list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
- queue_work(priv->wq, &vbl_ctrl->work);
+ queue_kthread_work(&priv->disp_thread[crtc_id].worker, &vbl_ctrl->work);
return 0;
}
@@ -188,17 +188,27 @@ static int msm_unload(struct drm_device *dev)
struct msm_gpu *gpu = priv->gpu;
struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
struct vblank_event *vbl_ev, *tmp;
+ int i;
/* We must cancel and cleanup any pending vblank enable/disable
* work before drm_irq_uninstall() to avoid work re-enabling an
* irq after uninstall has disabled it.
*/
- cancel_work_sync(&vbl_ctrl->work);
+ flush_kthread_work(&vbl_ctrl->work);
list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
list_del(&vbl_ev->node);
kfree(vbl_ev);
}
+ /* clean up display commit worker threads */
+ for (i = 0; i < priv->num_crtcs; i++) {
+ if (priv->disp_thread[i].thread) {
+ flush_kthread_worker(&priv->disp_thread[i].worker);
+ kthread_stop(priv->disp_thread[i].thread);
+ priv->disp_thread[i].thread = NULL;
+ }
+ }
+
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
drm_vblank_cleanup(dev);
@@ -358,7 +368,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
struct platform_device *pdev = dev->platformdev;
struct msm_drm_private *priv;
struct msm_kms *kms;
- int ret;
+ int ret, i;
priv = platform_get_drvdata(pdev);
if (!priv) {
@@ -410,6 +420,29 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
priv->kms = kms;
+ /* initialize commit thread structure */
+ for (i = 0; i < priv->num_crtcs; i++) {
+ priv->disp_thread[i].crtc_id = priv->crtcs[i]->base.id;
+ init_kthread_worker(&priv->disp_thread[i].worker);
+ priv->disp_thread[i].dev = dev;
+ priv->disp_thread[i].thread =
+ kthread_run(kthread_worker_fn,
+ &priv->disp_thread[i].worker,
+ "crtc_commit:%d",
+ priv->disp_thread[i].crtc_id);
+
+ if (IS_ERR(priv->disp_thread[i].thread)) {
+ dev_err(dev->dev, "failed to create kthread\n");
+ priv->disp_thread[i].thread = NULL;
+ /* clean up previously created threads if any */
+ for (i -= 1; i >= 0; i--) {
+ kthread_stop(priv->disp_thread[i].thread);
+ priv->disp_thread[i].thread = NULL;
+ }
+ goto fail;
+ }
+ }
+
if (kms) {
pm_runtime_enable(dev->dev);
ret = kms->funcs->hw_init(kms);
@@ -1678,7 +1711,7 @@ static int msm_pdev_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&priv->inactive_list);
INIT_LIST_HEAD(&priv->fence_cbs);
INIT_LIST_HEAD(&priv->vblank_ctrl.event_list);
- INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker);
+ init_kthread_work(&priv->vblank_ctrl.work, vblank_ctrl_worker);
spin_lock_init(&priv->vblank_ctrl.lock);
platform_set_drvdata(pdev, priv);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 959f7d36f464..78c6120eb2a5 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -33,6 +33,7 @@
#include <linux/of_graph.h>
#include <linux/mdss_io_util.h>
#include <asm/sizes.h>
+#include <linux/kthread.h>
#ifndef CONFIG_OF
#include <mach/board.h>
@@ -147,7 +148,7 @@ enum msm_mdp_conn_property {
};
struct msm_vblank_ctrl {
- struct work_struct work;
+ struct kthread_work work;
struct list_head event_list;
spinlock_t lock;
};
@@ -229,6 +230,14 @@ struct msm_drm_event {
u8 data[];
};
+/* Commit thread specific structure */
+struct msm_drm_commit {
+ struct drm_device *dev;
+ struct task_struct *thread;
+ unsigned int crtc_id;
+ struct kthread_worker worker;
+};
+
struct msm_drm_private {
struct msm_kms *kms;
@@ -287,6 +296,8 @@ struct msm_drm_private {
unsigned int num_crtcs;
struct drm_crtc *crtcs[MAX_CRTCS];
+ struct msm_drm_commit disp_thread[MAX_CRTCS];
+
unsigned int num_encoders;
struct drm_encoder *encoders[MAX_ENCODERS];