summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/gpu/drm/msm/msm_drv.c
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/gpu/drm/msm/msm_drv.c
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/gpu/drm/msm/msm_drv.c')
-rw-r--r--kernel/drivers/gpu/drm/msm/msm_drv.c150
1 files changed, 114 insertions, 36 deletions
diff --git a/kernel/drivers/gpu/drm/msm/msm_drv.c b/kernel/drivers/gpu/drm/msm/msm_drv.c
index c80a6bee2..b88ce514e 100644
--- a/kernel/drivers/gpu/drm/msm/msm_drv.c
+++ b/kernel/drivers/gpu/drm/msm/msm_drv.c
@@ -21,11 +21,9 @@
static void msm_fb_output_poll_changed(struct drm_device *dev)
{
-#ifdef CONFIG_DRM_MSM_FBDEV
struct msm_drm_private *priv = dev->dev_private;
if (priv->fbdev)
drm_fb_helper_hotplug_event(priv->fbdev);
-#endif
}
static const struct drm_mode_config_funcs mode_config_funcs = {
@@ -56,7 +54,7 @@ module_param(reglog, bool, 0600);
#define reglog 0
#endif
-#ifdef CONFIG_DRM_MSM_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
static bool fbdev = true;
MODULE_PARM_DESC(fbdev, "Enable fbdev compat layer");
module_param(fbdev, bool, 0600);
@@ -116,6 +114,65 @@ u32 msm_readl(const void __iomem *addr)
return val;
}
+struct vblank_event {
+ struct list_head node;
+ int crtc_id;
+ bool enable;
+};
+
+static void vblank_ctrl_worker(struct work_struct *work)
+{
+ struct msm_vblank_ctrl *vbl_ctrl = container_of(work,
+ struct msm_vblank_ctrl, work);
+ struct msm_drm_private *priv = container_of(vbl_ctrl,
+ struct msm_drm_private, vblank_ctrl);
+ struct msm_kms *kms = priv->kms;
+ struct vblank_event *vbl_ev, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vbl_ctrl->lock, flags);
+ list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
+ list_del(&vbl_ev->node);
+ spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+
+ if (vbl_ev->enable)
+ kms->funcs->enable_vblank(kms,
+ priv->crtcs[vbl_ev->crtc_id]);
+ else
+ kms->funcs->disable_vblank(kms,
+ priv->crtcs[vbl_ev->crtc_id]);
+
+ kfree(vbl_ev);
+
+ spin_lock_irqsave(&vbl_ctrl->lock, flags);
+ }
+
+ spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+}
+
+static int vblank_ctrl_queue_work(struct msm_drm_private *priv,
+ int crtc_id, bool enable)
+{
+ struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
+ struct vblank_event *vbl_ev;
+ unsigned long flags;
+
+ vbl_ev = kzalloc(sizeof(*vbl_ev), GFP_ATOMIC);
+ if (!vbl_ev)
+ return -ENOMEM;
+
+ vbl_ev->crtc_id = crtc_id;
+ vbl_ev->enable = enable;
+
+ spin_lock_irqsave(&vbl_ctrl->lock, flags);
+ list_add_tail(&vbl_ev->node, &vbl_ctrl->event_list);
+ spin_unlock_irqrestore(&vbl_ctrl->lock, flags);
+
+ queue_work(priv->wq, &vbl_ctrl->work);
+
+ return 0;
+}
+
/*
* DRM operations:
*/
@@ -125,6 +182,18 @@ static int msm_unload(struct drm_device *dev)
struct msm_drm_private *priv = dev->dev_private;
struct msm_kms *kms = priv->kms;
struct msm_gpu *gpu = priv->gpu;
+ struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl;
+ struct vblank_event *vbl_ev, *tmp;
+
+ /* 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);
+ list_for_each_entry_safe(vbl_ev, tmp, &vbl_ctrl->event_list, node) {
+ list_del(&vbl_ev->node);
+ kfree(vbl_ev);
+ }
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
@@ -282,6 +351,9 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
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);
+ spin_lock_init(&priv->vblank_ctrl.lock);
drm_mode_config_init(dev);
@@ -331,10 +403,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
}
}
- dev->mode_config.min_width = 0;
- dev->mode_config.min_height = 0;
- dev->mode_config.max_width = 2048;
- dev->mode_config.max_height = 2048;
dev->mode_config.funcs = &mode_config_funcs;
ret = drm_vblank_init(dev, priv->num_crtcs);
@@ -353,7 +421,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
drm_mode_config_reset(dev);
-#ifdef CONFIG_DRM_MSM_FBDEV
+#ifdef CONFIG_DRM_FBDEV_EMULATION
if (fbdev)
priv->fbdev = msm_fbdev_init(dev);
#endif
@@ -421,11 +489,9 @@ static void msm_preclose(struct drm_device *dev, struct drm_file *file)
static void msm_lastclose(struct drm_device *dev)
{
-#ifdef CONFIG_DRM_MSM_FBDEV
struct msm_drm_private *priv = dev->dev_private;
if (priv->fbdev)
drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
-#endif
}
static irqreturn_t msm_irq(int irq, void *arg)
@@ -461,24 +527,24 @@ static void msm_irq_uninstall(struct drm_device *dev)
kms->funcs->irq_uninstall(kms);
}
-static int msm_enable_vblank(struct drm_device *dev, int crtc_id)
+static int msm_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_kms *kms = priv->kms;
if (!kms)
return -ENXIO;
- DBG("dev=%p, crtc=%d", dev, crtc_id);
- return kms->funcs->enable_vblank(kms, priv->crtcs[crtc_id]);
+ DBG("dev=%p, crtc=%u", dev, pipe);
+ return vblank_ctrl_queue_work(priv, pipe, true);
}
-static void msm_disable_vblank(struct drm_device *dev, int crtc_id)
+static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
struct msm_drm_private *priv = dev->dev_private;
struct msm_kms *kms = priv->kms;
if (!kms)
return;
- DBG("dev=%p, crtc=%d", dev, crtc_id);
- kms->funcs->disable_vblank(kms, priv->crtcs[crtc_id]);
+ DBG("dev=%p, crtc=%u", dev, pipe);
+ vblank_ctrl_queue_work(priv, pipe, false);
}
/*
@@ -637,8 +703,8 @@ static void msm_debugfs_cleanup(struct drm_minor *minor)
* Fences:
*/
-int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
- struct timespec *timeout)
+int msm_wait_fence(struct drm_device *dev, uint32_t fence,
+ ktime_t *timeout , bool interruptible)
{
struct msm_drm_private *priv = dev->dev_private;
int ret;
@@ -656,16 +722,23 @@ int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
/* no-wait: */
ret = fence_completed(dev, fence) ? 0 : -EBUSY;
} else {
- unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
- unsigned long start_jiffies = jiffies;
+ ktime_t now = ktime_get();
unsigned long remaining_jiffies;
- if (time_after(start_jiffies, timeout_jiffies))
+ if (ktime_compare(*timeout, now) < 0) {
remaining_jiffies = 0;
- else
- remaining_jiffies = timeout_jiffies - start_jiffies;
+ } else {
+ ktime_t rem = ktime_sub(*timeout, now);
+ struct timespec ts = ktime_to_timespec(rem);
+ remaining_jiffies = timespec_to_jiffies(&ts);
+ }
- ret = wait_event_interruptible_timeout(priv->fence_event,
+ if (interruptible)
+ ret = wait_event_interruptible_timeout(priv->fence_event,
+ fence_completed(dev, fence),
+ remaining_jiffies);
+ else
+ ret = wait_event_timeout(priv->fence_event,
fence_completed(dev, fence),
remaining_jiffies);
@@ -772,13 +845,17 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data,
args->flags, &args->handle);
}
-#define TS(t) ((struct timespec){ .tv_sec = (t).tv_sec, .tv_nsec = (t).tv_nsec })
+static inline ktime_t to_ktime(struct drm_msm_timespec timeout)
+{
+ return ktime_set(timeout.tv_sec, timeout.tv_nsec);
+}
static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_msm_gem_cpu_prep *args = data;
struct drm_gem_object *obj;
+ ktime_t timeout = to_ktime(args->timeout);
int ret;
if (args->op & ~MSM_PREP_FLAGS) {
@@ -790,7 +867,7 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
if (!obj)
return -ENOENT;
- ret = msm_gem_cpu_prep(obj, args->op, &TS(args->timeout));
+ ret = msm_gem_cpu_prep(obj, args->op, &timeout);
drm_gem_object_unreference_unlocked(obj);
@@ -840,24 +917,24 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_msm_wait_fence *args = data;
+ ktime_t timeout = to_ktime(args->timeout);
if (args->pad) {
DRM_ERROR("invalid pad: %08x\n", args->pad);
return -EINVAL;
}
- return msm_wait_fence_interruptable(dev, args->fence,
- &TS(args->timeout));
+ return msm_wait_fence(dev, args->fence, &timeout, true);
}
static const struct drm_ioctl_desc msm_ioctls[] = {
- DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(MSM_GEM_INFO, msm_ioctl_gem_info, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_UNLOCKED|DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GEM_INFO, msm_ioctl_gem_info, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_PREP, msm_ioctl_gem_cpu_prep, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GEM_CPU_FINI, msm_ioctl_gem_cpu_fini, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_GEM_SUBMIT, msm_ioctl_gem_submit, DRM_AUTH|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_AUTH|DRM_RENDER_ALLOW),
};
static const struct vm_operations_struct vm_ops = {
@@ -885,6 +962,7 @@ static struct drm_driver msm_driver = {
DRIVER_GEM |
DRIVER_PRIME |
DRIVER_RENDER |
+ DRIVER_ATOMIC |
DRIVER_MODESET,
.load = msm_load,
.unload = msm_unload,
@@ -896,7 +974,7 @@ static struct drm_driver msm_driver = {
.irq_preinstall = msm_irq_preinstall,
.irq_postinstall = msm_irq_postinstall,
.irq_uninstall = msm_irq_uninstall,
- .get_vblank_counter = drm_vblank_count,
+ .get_vblank_counter = drm_vblank_no_hw_counter,
.enable_vblank = msm_enable_vblank,
.disable_vblank = msm_disable_vblank,
.gem_free_object = msm_gem_free_object,