From feb46f02c3fa70e6d3e5307cb105cc69c60a3fe3 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sun, 20 Mar 2016 10:16:29 -0400 Subject: [PATCH 01/25] drm/msm: make HDCP support optional It is already optional at runtime. But this at least simplifies backports to kernels without QCOM_SCM. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Kconfig | 7 +++++++ drivers/gpu/drm/msm/Makefile | 3 ++- drivers/gpu/drm/msm/hdmi/hdmi.h | 11 +++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 215495c2780c0..167a4971f47c5 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -23,6 +23,13 @@ config DRM_MSM_REGISTER_LOGGING that can be parsed by envytools demsm tool. If enabled, register logging can be switched on via msm.reglog=y module param. +config DRM_MSM_HDMI_HDCP + bool "Enable HDMI HDCP support in MSM DRM driver" + depends on DRM_MSM && QCOM_SCM + default y + help + Choose this option to enable HDCP state machine + config DRM_MSM_DSI bool "Enable DSI support in MSM DRM driver" depends on DRM_MSM diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index ddb4c9d097e45..d7cf79635e73e 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -10,7 +10,6 @@ msm-y := \ hdmi/hdmi_audio.o \ hdmi/hdmi_bridge.o \ hdmi/hdmi_connector.o \ - hdmi/hdmi_hdcp.o \ hdmi/hdmi_i2c.o \ hdmi/hdmi_phy.o \ hdmi/hdmi_phy_8960.o \ @@ -56,6 +55,8 @@ msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_pll_8960.o msm-$(CONFIG_COMMON_CLK) += hdmi/hdmi_phy_8996.o +msm-$(CONFIG_DRM_MSM_HDMI_HDCP) += hdmi/hdmi_hdcp.o + msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ mdp/mdp4/mdp4_dsi_encoder.o \ dsi/dsi_cfg.o \ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 65428cf233ce3..bc7ba0bdee072 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -243,10 +243,21 @@ struct i2c_adapter *msm_hdmi_i2c_init(struct hdmi *hdmi); /* * hdcp */ +#ifdef CONFIG_DRM_MSM_HDMI_HDCP struct hdmi_hdcp_ctrl *msm_hdmi_hdcp_init(struct hdmi *hdmi); void msm_hdmi_hdcp_destroy(struct hdmi *hdmi); void msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl); void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl); void msm_hdmi_hdcp_irq(struct hdmi_hdcp_ctrl *hdcp_ctrl); +#else +static inline struct hdmi_hdcp_ctrl *msm_hdmi_hdcp_init(struct hdmi *hdmi) +{ + return ERR_PTR(-ENXIO); +} +static inline void msm_hdmi_hdcp_destroy(struct hdmi *hdmi) {} +static inline void msm_hdmi_hdcp_on(struct hdmi_hdcp_ctrl *hdcp_ctrl) {} +static inline void msm_hdmi_hdcp_off(struct hdmi_hdcp_ctrl *hdcp_ctrl) {} +static inline void msm_hdmi_hdcp_irq(struct hdmi_hdcp_ctrl *hdcp_ctrl) {} +#endif #endif /* __HDMI_CONNECTOR_H__ */ From 824815c4cd13e384ef5a4be725ec4b06e4ad2c2a Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 31 Mar 2016 16:23:51 -0400 Subject: [PATCH 02/25] reservation: add reservation_object_get_excl_rcu() In the atomic modesetting path, each driver simply wants to grab a ref to the exclusive fence from a reservation object to store in the incoming drm_plane_state, without doing the whole RCU dance. Since each driver will need to do this, lets make a helper. v2: rename to _rcu instead of _unlocked to be more consistent Signed-off-by: Rob Clark Acked-by: Sumit Semwal --- include/linux/reservation.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/linux/reservation.h b/include/linux/reservation.h index 5a0b64cf68b4a..49d057655d62b 100644 --- a/include/linux/reservation.h +++ b/include/linux/reservation.h @@ -120,6 +120,24 @@ reservation_object_get_excl(struct reservation_object *obj) reservation_object_held(obj)); } +static inline struct fence * +reservation_object_get_excl_rcu(struct reservation_object *obj) +{ + struct fence *fence; + unsigned seq; +retry: + seq = read_seqcount_begin(&obj->seq); + rcu_read_lock(); + fence = rcu_dereference(obj->fence_excl); + if (read_seqcount_retry(&obj->seq, seq)) { + rcu_read_unlock(); + goto retry; + } + fence = fence_get(fence); + rcu_read_unlock(); + return fence; +} + int reservation_object_reserve_shared(struct reservation_object *obj); void reservation_object_add_shared_fence(struct reservation_object *obj, struct fence *fence); From edcd60ce243d16f1b50dacb8f0643308b23f1070 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 16 Mar 2016 12:56:12 -0400 Subject: [PATCH 03/25] drm/msm: move debugfs code to it's own file Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/msm_debugfs.c | 168 ++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_debugfs.h | 26 +++++ drivers/gpu/drm/msm/msm_drv.c | 153 +-------------------------- 4 files changed, 196 insertions(+), 152 deletions(-) create mode 100644 drivers/gpu/drm/msm/msm_debugfs.c create mode 100644 drivers/gpu/drm/msm/msm_debugfs.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index d7cf79635e73e..07422519481dd 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -39,6 +39,7 @@ msm-y := \ mdp/mdp5/mdp5_plane.o \ mdp/mdp5/mdp5_smp.o \ msm_atomic.o \ + msm_debugfs.o \ msm_drv.o \ msm_fb.o \ msm_gem.o \ diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c new file mode 100644 index 0000000000000..663f2b6ef0919 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2013-2016 Red Hat + * Author: Rob Clark + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifdef CONFIG_DEBUG_FS +#include "msm_drv.h" +#include "msm_gpu.h" + +static int msm_gpu_show(struct drm_device *dev, struct seq_file *m) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_gpu *gpu = priv->gpu; + + if (gpu) { + seq_printf(m, "%s Status:\n", gpu->name); + gpu->funcs->show(gpu, m); + } + + return 0; +} + +static int msm_gem_show(struct drm_device *dev, struct seq_file *m) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_gpu *gpu = priv->gpu; + + if (gpu) { + seq_printf(m, "Active Objects (%s):\n", gpu->name); + msm_gem_describe_objects(&gpu->active_list, m); + } + + seq_printf(m, "Inactive Objects:\n"); + msm_gem_describe_objects(&priv->inactive_list, m); + + return 0; +} + +static int msm_mm_show(struct drm_device *dev, struct seq_file *m) +{ + return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm); +} + +static int msm_fb_show(struct drm_device *dev, struct seq_file *m) +{ + struct msm_drm_private *priv = dev->dev_private; + struct drm_framebuffer *fb, *fbdev_fb = NULL; + + if (priv->fbdev) { + seq_printf(m, "fbcon "); + fbdev_fb = priv->fbdev->fb; + msm_framebuffer_describe(fbdev_fb, m); + } + + mutex_lock(&dev->mode_config.fb_lock); + list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + if (fb == fbdev_fb) + continue; + + seq_printf(m, "user "); + msm_framebuffer_describe(fb, m); + } + mutex_unlock(&dev->mode_config.fb_lock); + + return 0; +} + +static int show_locked(struct seq_file *m, void *arg) +{ + struct drm_info_node *node = (struct drm_info_node *) m->private; + struct drm_device *dev = node->minor->dev; + int (*show)(struct drm_device *dev, struct seq_file *m) = + node->info_ent->data; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + ret = show(dev, m); + + mutex_unlock(&dev->struct_mutex); + + return ret; +} + +static struct drm_info_list msm_debugfs_list[] = { + {"gpu", show_locked, 0, msm_gpu_show}, + {"gem", show_locked, 0, msm_gem_show}, + { "mm", show_locked, 0, msm_mm_show }, + { "fb", show_locked, 0, msm_fb_show }, +}; + +static int late_init_minor(struct drm_minor *minor) +{ + int ret; + + if (!minor) + return 0; + + ret = msm_rd_debugfs_init(minor); + if (ret) { + dev_err(minor->dev->dev, "could not install rd debugfs\n"); + return ret; + } + + ret = msm_perf_debugfs_init(minor); + if (ret) { + dev_err(minor->dev->dev, "could not install perf debugfs\n"); + return ret; + } + + return 0; +} + +int msm_debugfs_late_init(struct drm_device *dev) +{ + int ret; + ret = late_init_minor(dev->primary); + if (ret) + return ret; + ret = late_init_minor(dev->render); + if (ret) + return ret; + ret = late_init_minor(dev->control); + return ret; +} + +int msm_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + int ret; + + ret = drm_debugfs_create_files(msm_debugfs_list, + ARRAY_SIZE(msm_debugfs_list), + minor->debugfs_root, minor); + + if (ret) { + dev_err(dev->dev, "could not install msm_debugfs_list\n"); + return ret; + } + + return 0; +} + +void msm_debugfs_cleanup(struct drm_minor *minor) +{ + drm_debugfs_remove_files(msm_debugfs_list, + ARRAY_SIZE(msm_debugfs_list), minor); + if (!minor->dev->dev_private) + return; + msm_rd_debugfs_cleanup(minor); + msm_perf_debugfs_cleanup(minor); +} +#endif + diff --git a/drivers/gpu/drm/msm/msm_debugfs.h b/drivers/gpu/drm/msm/msm_debugfs.h new file mode 100644 index 0000000000000..6110c972fd15a --- /dev/null +++ b/drivers/gpu/drm/msm/msm_debugfs.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016 Red Hat + * Author: Rob Clark + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __MSM_DEBUGFS_H__ +#define __MSM_DEBUGFS_H__ + +#ifdef CONFIG_DEBUG_FS +int msm_debugfs_init(struct drm_minor *minor); +void msm_debugfs_cleanup(struct drm_minor *minor); +#endif + +#endif /* __MSM_DEBUGFS_H__ */ diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c03b96709179b..c0467f90af02f 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -16,6 +16,7 @@ */ #include "msm_drv.h" +#include "msm_debugfs.h" #include "msm_gpu.h" #include "msm_kms.h" @@ -535,158 +536,6 @@ static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) vblank_ctrl_queue_work(priv, pipe, false); } -/* - * DRM debugfs: - */ - -#ifdef CONFIG_DEBUG_FS -static int msm_gpu_show(struct drm_device *dev, struct seq_file *m) -{ - struct msm_drm_private *priv = dev->dev_private; - struct msm_gpu *gpu = priv->gpu; - - if (gpu) { - seq_printf(m, "%s Status:\n", gpu->name); - gpu->funcs->show(gpu, m); - } - - return 0; -} - -static int msm_gem_show(struct drm_device *dev, struct seq_file *m) -{ - struct msm_drm_private *priv = dev->dev_private; - struct msm_gpu *gpu = priv->gpu; - - if (gpu) { - seq_printf(m, "Active Objects (%s):\n", gpu->name); - msm_gem_describe_objects(&gpu->active_list, m); - } - - seq_printf(m, "Inactive Objects:\n"); - msm_gem_describe_objects(&priv->inactive_list, m); - - return 0; -} - -static int msm_mm_show(struct drm_device *dev, struct seq_file *m) -{ - return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm); -} - -static int msm_fb_show(struct drm_device *dev, struct seq_file *m) -{ - struct msm_drm_private *priv = dev->dev_private; - struct drm_framebuffer *fb, *fbdev_fb = NULL; - - if (priv->fbdev) { - seq_printf(m, "fbcon "); - fbdev_fb = priv->fbdev->fb; - msm_framebuffer_describe(fbdev_fb, m); - } - - mutex_lock(&dev->mode_config.fb_lock); - list_for_each_entry(fb, &dev->mode_config.fb_list, head) { - if (fb == fbdev_fb) - continue; - - seq_printf(m, "user "); - msm_framebuffer_describe(fb, m); - } - mutex_unlock(&dev->mode_config.fb_lock); - - return 0; -} - -static int show_locked(struct seq_file *m, void *arg) -{ - struct drm_info_node *node = (struct drm_info_node *) m->private; - struct drm_device *dev = node->minor->dev; - int (*show)(struct drm_device *dev, struct seq_file *m) = - node->info_ent->data; - int ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; - - ret = show(dev, m); - - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -static struct drm_info_list msm_debugfs_list[] = { - {"gpu", show_locked, 0, msm_gpu_show}, - {"gem", show_locked, 0, msm_gem_show}, - { "mm", show_locked, 0, msm_mm_show }, - { "fb", show_locked, 0, msm_fb_show }, -}; - -static int late_init_minor(struct drm_minor *minor) -{ - int ret; - - if (!minor) - return 0; - - ret = msm_rd_debugfs_init(minor); - if (ret) { - dev_err(minor->dev->dev, "could not install rd debugfs\n"); - return ret; - } - - ret = msm_perf_debugfs_init(minor); - if (ret) { - dev_err(minor->dev->dev, "could not install perf debugfs\n"); - return ret; - } - - return 0; -} - -int msm_debugfs_late_init(struct drm_device *dev) -{ - int ret; - ret = late_init_minor(dev->primary); - if (ret) - return ret; - ret = late_init_minor(dev->render); - if (ret) - return ret; - ret = late_init_minor(dev->control); - return ret; -} - -static int msm_debugfs_init(struct drm_minor *minor) -{ - struct drm_device *dev = minor->dev; - int ret; - - ret = drm_debugfs_create_files(msm_debugfs_list, - ARRAY_SIZE(msm_debugfs_list), - minor->debugfs_root, minor); - - if (ret) { - dev_err(dev->dev, "could not install msm_debugfs_list\n"); - return ret; - } - - return 0; -} - -static void msm_debugfs_cleanup(struct drm_minor *minor) -{ - drm_debugfs_remove_files(msm_debugfs_list, - ARRAY_SIZE(msm_debugfs_list), minor); - if (!minor->dev->dev_private) - return; - msm_rd_debugfs_cleanup(minor); - msm_perf_debugfs_cleanup(minor); -} -#endif - /* * Fences: */ From fde5de6cb4617a160a6cc5c034284618350c2961 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 15 Mar 2016 15:35:08 -0400 Subject: [PATCH 04/25] drm/msm: move fence code to it's own file Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/Makefile | 1 + drivers/gpu/drm/msm/msm_atomic.c | 1 + drivers/gpu/drm/msm/msm_drv.c | 108 +------------------------- drivers/gpu/drm/msm/msm_drv.h | 27 +------ drivers/gpu/drm/msm/msm_fence.c | 129 +++++++++++++++++++++++++++++++ drivers/gpu/drm/msm/msm_fence.h | 43 +++++++++++ drivers/gpu/drm/msm/msm_gem.c | 1 + drivers/gpu/drm/msm/msm_gpu.c | 1 + 8 files changed, 178 insertions(+), 133 deletions(-) create mode 100644 drivers/gpu/drm/msm/msm_fence.c create mode 100644 drivers/gpu/drm/msm/msm_fence.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 07422519481dd..60cb02624dc0b 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -42,6 +42,7 @@ msm-y := \ msm_debugfs.o \ msm_drv.o \ msm_fb.o \ + msm_fence.o \ msm_gem.o \ msm_gem_prime.o \ msm_gem_submit.o \ diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 5c6130969f4d5..fab0c2d41f66d 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -18,6 +18,7 @@ #include "msm_drv.h" #include "msm_kms.h" #include "msm_gem.h" +#include "msm_fence.h" struct msm_commit { struct drm_device *dev; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c0467f90af02f..d4a1a11ccc432 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -17,6 +17,7 @@ #include "msm_drv.h" #include "msm_debugfs.h" +#include "msm_fence.h" #include "msm_gpu.h" #include "msm_kms.h" @@ -536,113 +537,6 @@ static void msm_disable_vblank(struct drm_device *dev, unsigned int pipe) vblank_ctrl_queue_work(priv, pipe, false); } -/* - * Fences: - */ - -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; - - if (!priv->gpu) - return 0; - - if (fence > priv->gpu->submitted_fence) { - DRM_ERROR("waiting on invalid fence: %u (of %u)\n", - fence, priv->gpu->submitted_fence); - return -EINVAL; - } - - if (!timeout) { - /* no-wait: */ - ret = fence_completed(dev, fence) ? 0 : -EBUSY; - } else { - ktime_t now = ktime_get(); - unsigned long remaining_jiffies; - - if (ktime_compare(*timeout, now) < 0) { - remaining_jiffies = 0; - } else { - ktime_t rem = ktime_sub(*timeout, now); - struct timespec ts = ktime_to_timespec(rem); - remaining_jiffies = timespec_to_jiffies(&ts); - } - - 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); - - if (ret == 0) { - DBG("timeout waiting for fence: %u (completed: %u)", - fence, priv->completed_fence); - ret = -ETIMEDOUT; - } else if (ret != -ERESTARTSYS) { - ret = 0; - } - } - - return ret; -} - -int msm_queue_fence_cb(struct drm_device *dev, - struct msm_fence_cb *cb, uint32_t fence) -{ - struct msm_drm_private *priv = dev->dev_private; - int ret = 0; - - mutex_lock(&dev->struct_mutex); - if (!list_empty(&cb->work.entry)) { - ret = -EINVAL; - } else if (fence > priv->completed_fence) { - cb->fence = fence; - list_add_tail(&cb->work.entry, &priv->fence_cbs); - } else { - queue_work(priv->wq, &cb->work); - } - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -/* called from workqueue */ -void msm_update_fence(struct drm_device *dev, uint32_t fence) -{ - struct msm_drm_private *priv = dev->dev_private; - - mutex_lock(&dev->struct_mutex); - priv->completed_fence = max(fence, priv->completed_fence); - - while (!list_empty(&priv->fence_cbs)) { - struct msm_fence_cb *cb; - - cb = list_first_entry(&priv->fence_cbs, - struct msm_fence_cb, work.entry); - - if (cb->fence > priv->completed_fence) - break; - - list_del_init(&cb->work.entry); - queue_work(priv->wq, &cb->work); - } - - mutex_unlock(&dev->struct_mutex); - - wake_up_all(&priv->fence_event); -} - -void __msm_fence_worker(struct work_struct *work) -{ - struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work); - cb->func(cb); -} - /* * DRM ioctls: */ diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 0b8b0e630e42a..67a1e4ce755c7 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -49,6 +49,7 @@ struct msm_mmu; struct msm_rd_state; struct msm_perf_state; struct msm_gem_submit; +struct msm_fence_cb; #define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */ @@ -157,20 +158,6 @@ struct msm_format { uint32_t pixel_format; }; -/* callback from wq once fence has passed: */ -struct msm_fence_cb { - struct work_struct work; - uint32_t fence; - void (*func)(struct msm_fence_cb *cb); -}; - -void __msm_fence_worker(struct work_struct *work); - -#define INIT_FENCE_CB(_cb, _func) do { \ - INIT_WORK(&(_cb)->work, __msm_fence_worker); \ - (_cb)->func = _func; \ - } while (0) - int msm_atomic_check(struct drm_device *dev, struct drm_atomic_state *state); int msm_atomic_commit(struct drm_device *dev, @@ -178,12 +165,6 @@ int msm_atomic_commit(struct drm_device *dev, int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); -int msm_wait_fence(struct drm_device *dev, uint32_t fence, - ktime_t *timeout, bool interruptible); -int msm_queue_fence_cb(struct drm_device *dev, - struct msm_fence_cb *cb, uint32_t fence); -void msm_update_fence(struct drm_device *dev, uint32_t fence); - int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); @@ -303,12 +284,6 @@ u32 msm_readl(const void __iomem *addr); #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) -static inline bool fence_completed(struct drm_device *dev, uint32_t fence) -{ - struct msm_drm_private *priv = dev->dev_private; - return priv->completed_fence >= fence; -} - static inline int align_pitch(int width, int bpp) { int bytespp = (bpp + 7) / 8; diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c new file mode 100644 index 0000000000000..55a5f9280088c --- /dev/null +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2013-2016 Red Hat + * Author: Rob Clark + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "msm_drv.h" +#include "msm_fence.h" +#include "msm_gpu.h" + +static inline bool fence_completed(struct drm_device *dev, uint32_t fence) +{ + struct msm_drm_private *priv = dev->dev_private; + return (int32_t)(priv->completed_fence - fence) >= 0; +} + +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; + + if (!priv->gpu) + return 0; + + if (fence > priv->gpu->submitted_fence) { + DRM_ERROR("waiting on invalid fence: %u (of %u)\n", + fence, priv->gpu->submitted_fence); + return -EINVAL; + } + + if (!timeout) { + /* no-wait: */ + ret = fence_completed(dev, fence) ? 0 : -EBUSY; + } else { + ktime_t now = ktime_get(); + unsigned long remaining_jiffies; + + if (ktime_compare(*timeout, now) < 0) { + remaining_jiffies = 0; + } else { + ktime_t rem = ktime_sub(*timeout, now); + struct timespec ts = ktime_to_timespec(rem); + remaining_jiffies = timespec_to_jiffies(&ts); + } + + 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); + + if (ret == 0) { + DBG("timeout waiting for fence: %u (completed: %u)", + fence, priv->completed_fence); + ret = -ETIMEDOUT; + } else if (ret != -ERESTARTSYS) { + ret = 0; + } + } + + return ret; +} + +int msm_queue_fence_cb(struct drm_device *dev, + struct msm_fence_cb *cb, uint32_t fence) +{ + struct msm_drm_private *priv = dev->dev_private; + int ret = 0; + + mutex_lock(&dev->struct_mutex); + if (!list_empty(&cb->work.entry)) { + ret = -EINVAL; + } else if (fence > priv->completed_fence) { + cb->fence = fence; + list_add_tail(&cb->work.entry, &priv->fence_cbs); + } else { + queue_work(priv->wq, &cb->work); + } + mutex_unlock(&dev->struct_mutex); + + return ret; +} + +/* called from workqueue */ +void msm_update_fence(struct drm_device *dev, uint32_t fence) +{ + struct msm_drm_private *priv = dev->dev_private; + + mutex_lock(&dev->struct_mutex); + priv->completed_fence = max(fence, priv->completed_fence); + + while (!list_empty(&priv->fence_cbs)) { + struct msm_fence_cb *cb; + + cb = list_first_entry(&priv->fence_cbs, + struct msm_fence_cb, work.entry); + + if (cb->fence > priv->completed_fence) + break; + + list_del_init(&cb->work.entry); + queue_work(priv->wq, &cb->work); + } + + mutex_unlock(&dev->struct_mutex); + + wake_up_all(&priv->fence_event); +} + +void __msm_fence_worker(struct work_struct *work) +{ + struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work); + cb->func(cb); +} diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h new file mode 100644 index 0000000000000..6ddb81c2c3666 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2013-2016 Red Hat + * Author: Rob Clark + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __MSM_FENCE_H__ +#define __MSM_FENCE_H__ + +#include "msm_drv.h" + +/* callback from wq once fence has passed: */ +struct msm_fence_cb { + struct work_struct work; + uint32_t fence; + void (*func)(struct msm_fence_cb *cb); +}; + +void __msm_fence_worker(struct work_struct *work); + +#define INIT_FENCE_CB(_cb, _func) do { \ + INIT_WORK(&(_cb)->work, __msm_fence_worker); \ + (_cb)->func = _func; \ + } while (0) + +int msm_wait_fence(struct drm_device *dev, uint32_t fence, + ktime_t *timeout, bool interruptible); +int msm_queue_fence_cb(struct drm_device *dev, + struct msm_fence_cb *cb, uint32_t fence); +void msm_update_fence(struct drm_device *dev, uint32_t fence); + +#endif diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 3cedb8d5c855a..ef03ee7e58386 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -21,6 +21,7 @@ #include #include "msm_drv.h" +#include "msm_fence.h" #include "msm_gem.h" #include "msm_gpu.h" #include "msm_mmu.h" diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 6b02ada6579a7..5d4af3ec8f46e 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -18,6 +18,7 @@ #include "msm_gpu.h" #include "msm_gem.h" #include "msm_mmu.h" +#include "msm_fence.h" /* From 79f0e20215bb902352cf7eb31222f4120563775c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 16 Mar 2016 12:40:35 -0400 Subject: [PATCH 05/25] drm/msm: use imported dmabuf's reservation object This was always the intention, but somehow it was never wired up properly. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.h | 2 +- drivers/gpu/drm/msm/msm_gem.c | 18 ++++++++++++------ drivers/gpu/drm/msm/msm_gem_prime.c | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 67a1e4ce755c7..86b7b3796d8f0 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -208,7 +208,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32_t flags); struct drm_gem_object *msm_gem_import(struct drm_device *dev, - uint32_t size, struct sg_table *sgt); + struct dma_buf *dmabuf, struct sg_table *sgt); int msm_framebuffer_prepare(struct drm_framebuffer *fb, int id); void msm_framebuffer_cleanup(struct drm_framebuffer *fb, int id); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index ef03ee7e58386..09e2190a09ed1 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -584,6 +584,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, static int msm_gem_new_impl(struct drm_device *dev, uint32_t size, uint32_t flags, + struct reservation_object *resv, struct drm_gem_object **obj) { struct msm_drm_private *priv = dev->dev_private; @@ -623,8 +624,12 @@ static int msm_gem_new_impl(struct drm_device *dev, msm_obj->flags = flags; - msm_obj->resv = &msm_obj->_resv; - reservation_object_init(msm_obj->resv); + if (resv) { + msm_obj->resv = resv; + } else { + msm_obj->resv = &msm_obj->_resv; + reservation_object_init(msm_obj->resv); + } INIT_LIST_HEAD(&msm_obj->submit_entry); list_add_tail(&msm_obj->mm_list, &priv->inactive_list); @@ -644,7 +649,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, size = PAGE_ALIGN(size); - ret = msm_gem_new_impl(dev, size, flags, &obj); + ret = msm_gem_new_impl(dev, size, flags, NULL, &obj); if (ret) goto fail; @@ -666,10 +671,11 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, } struct drm_gem_object *msm_gem_import(struct drm_device *dev, - uint32_t size, struct sg_table *sgt) + struct dma_buf *dmabuf, struct sg_table *sgt) { struct msm_gem_object *msm_obj; struct drm_gem_object *obj; + uint32_t size; int ret, npages; /* if we don't have IOMMU, don't bother pretending we can import: */ @@ -678,9 +684,9 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, return ERR_PTR(-EINVAL); } - size = PAGE_ALIGN(size); + size = PAGE_ALIGN(dmabuf->size); - ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj); + ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj); if (ret) goto fail; diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c index 121975b07cd41..6b90890faffec 100644 --- a/drivers/gpu/drm/msm/msm_gem_prime.c +++ b/drivers/gpu/drm/msm/msm_gem_prime.c @@ -55,7 +55,7 @@ int msm_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, struct dma_buf_attachment *attach, struct sg_table *sg) { - return msm_gem_import(dev, attach->dmabuf->size, sg); + return msm_gem_import(dev, attach->dmabuf, sg); } int msm_gem_prime_pin(struct drm_gem_object *obj) From 340ff4104f4454f8f1c3bf793c46411115309545 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 16 Mar 2016 14:57:22 -0400 Subject: [PATCH 06/25] drm/msm: split out timeout_to_jiffies helper Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.h | 15 +++++++++++++++ drivers/gpu/drm/msm/msm_fence.c | 11 +---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 86b7b3796d8f0..af007ac8c7339 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -302,5 +302,20 @@ static inline int align_pitch(int width, int bpp) /* for conditionally setting boolean flag(s): */ #define COND(bool, val) ((bool) ? (val) : 0) +static inline unsigned long timeout_to_jiffies(const ktime_t *timeout) +{ + ktime_t now = ktime_get(); + unsigned long remaining_jiffies; + + if (ktime_compare(*timeout, now) < 0) { + remaining_jiffies = 0; + } else { + ktime_t rem = ktime_sub(*timeout, now); + struct timespec ts = ktime_to_timespec(rem); + remaining_jiffies = timespec_to_jiffies(&ts); + } + + return remaining_jiffies; +} #endif /* __MSM_DRV_H__ */ diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index 55a5f9280088c..002eecb3934e4 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -44,16 +44,7 @@ int msm_wait_fence(struct drm_device *dev, uint32_t fence, /* no-wait: */ ret = fence_completed(dev, fence) ? 0 : -EBUSY; } else { - ktime_t now = ktime_get(); - unsigned long remaining_jiffies; - - if (ktime_compare(*timeout, now) < 0) { - remaining_jiffies = 0; - } else { - ktime_t rem = ktime_sub(*timeout, now); - struct timespec ts = ktime_to_timespec(rem); - remaining_jiffies = timespec_to_jiffies(&ts); - } + unsigned long remaining_jiffies = timeout_to_jiffies(timeout); if (interruptible) ret = wait_event_interruptible_timeout(priv->fence_event, From 7d12a279d421255792f2092f68262a79e3311dc2 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 16 Mar 2016 16:07:38 -0400 Subject: [PATCH 07/25] drm/msm/gpu: simplify tracking in-flight bo's Since we already track the array of bo's in the submit object, just unconditionally take and drop ref's per submit (rather than only taking ref's if bo is not already active). This simplifies later patches. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gpu.c | 51 +++++++++++++++-------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 5d4af3ec8f46e..80efe56b80f8f 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -432,6 +432,22 @@ int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime, * Cmdstream submission/retirement: */ +static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) +{ + int i; + + for (i = 0; i < submit->nr_bos; i++) { + struct msm_gem_object *msm_obj = submit->bos[i].obj; + /* move to inactive: */ + msm_gem_move_to_inactive(&msm_obj->base); + msm_gem_put_iova(&msm_obj->base, gpu->id); + drm_gem_object_unreference(&msm_obj->base); + } + + list_del(&submit->node); + kfree(submit); +} + static void retire_submits(struct msm_gpu *gpu, uint32_t fence) { struct drm_device *dev = gpu->dev; @@ -445,8 +461,7 @@ static void retire_submits(struct msm_gpu *gpu, uint32_t fence) struct msm_gem_submit, node); if (submit->fence <= fence) { - list_del(&submit->node); - kfree(submit); + retire_submit(gpu, submit); } else { break; } @@ -462,26 +477,7 @@ static void retire_worker(struct work_struct *work) msm_update_fence(gpu->dev, fence); mutex_lock(&dev->struct_mutex); - retire_submits(gpu, fence); - - while (!list_empty(&gpu->active_list)) { - struct msm_gem_object *obj; - - obj = list_first_entry(&gpu->active_list, - struct msm_gem_object, mm_list); - - if ((obj->read_fence <= fence) && - (obj->write_fence <= fence)) { - /* move to inactive: */ - msm_gem_move_to_inactive(&obj->base); - msm_gem_put_iova(&obj->base, gpu->id); - drm_gem_object_unreference(&obj->base); - } else { - break; - } - } - mutex_unlock(&dev->struct_mutex); if (!msm_gpu_active(gpu)) @@ -522,20 +518,17 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; + uint32_t iova; /* can't happen yet.. but when we add 2d support we'll have * to deal w/ cross-ring synchronization: */ WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); - if (!is_active(msm_obj)) { - uint32_t iova; - - /* ring takes a reference to the bo and iova: */ - drm_gem_object_reference(&msm_obj->base); - msm_gem_get_iova_locked(&msm_obj->base, - submit->gpu->id, &iova); - } + /* submit takes a reference to the bo and iova until retired: */ + drm_gem_object_reference(&msm_obj->base); + msm_gem_get_iova_locked(&msm_obj->base, + submit->gpu->id, &iova); if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); From 340faef2418989b2573b82e6c708ef9e24ca439b Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 14 Mar 2016 13:56:37 -0400 Subject: [PATCH 08/25] drm/msm: split locking and pinning BO's Split up locking and pinning buffers in the submit path. This is needed because we'll want to insert fencing in between the two steps. This makes things end up looking more similar to etnaviv submit code (which was originally modelled on the msm code but has already added 'struct fence' support). Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.h | 2 +- drivers/gpu/drm/msm/msm_gem_submit.c | 69 ++++++++++++++++------------ 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 6fc59bfeedeb5..b8904517117d5 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -100,7 +100,7 @@ struct msm_gem_submit { struct list_head bo_list; struct ww_acquire_ctx ticket; uint32_t fence; - bool valid; + bool valid; /* true if no cmdstream patching needed */ unsigned int nr_cmds; unsigned int nr_bos; struct { diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 43d2181231c08..b231544b3f52d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -24,7 +24,7 @@ */ /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ -#define BO_VALID 0x8000 +#define BO_VALID 0x8000 /* is current addr in cmdstream correct/valid? */ #define BO_LOCKED 0x4000 #define BO_PINNED 0x2000 @@ -136,16 +136,13 @@ static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) } /* This is where we make sure all the bo's are reserved and pin'd: */ -static int submit_validate_objects(struct msm_gem_submit *submit) +static int submit_lock_objects(struct msm_gem_submit *submit) { int contended, slow_locked = -1, i, ret = 0; retry: - submit->valid = true; - for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; - uint32_t iova; if (slow_locked == i) slow_locked = -1; @@ -159,30 +156,6 @@ static int submit_validate_objects(struct msm_gem_submit *submit) goto fail; submit->bos[i].flags |= BO_LOCKED; } - - - /* if locking succeeded, pin bo: */ - ret = msm_gem_get_iova_locked(&msm_obj->base, - submit->gpu->id, &iova); - - /* this would break the logic in the fail path.. there is no - * reason for this to happen, but just to be on the safe side - * let's notice if this starts happening in the future: - */ - WARN_ON(ret == -EDEADLK); - - if (ret) - goto fail; - - submit->bos[i].flags |= BO_PINNED; - - if (iova == submit->bos[i].iova) { - submit->bos[i].flags |= BO_VALID; - } else { - submit->bos[i].iova = iova; - submit->bos[i].flags &= ~BO_VALID; - submit->valid = false; - } } ww_acquire_done(&submit->ticket); @@ -211,6 +184,38 @@ static int submit_validate_objects(struct msm_gem_submit *submit) return ret; } +static int submit_pin_objects(struct msm_gem_submit *submit) +{ + int i, ret = 0; + + submit->valid = true; + + for (i = 0; i < submit->nr_bos; i++) { + struct msm_gem_object *msm_obj = submit->bos[i].obj; + uint32_t iova; + + /* if locking succeeded, pin bo: */ + ret = msm_gem_get_iova_locked(&msm_obj->base, + submit->gpu->id, &iova); + + if (ret) + break; + + submit->bos[i].flags |= BO_PINNED; + + if (iova == submit->bos[i].iova) { + submit->bos[i].flags |= BO_VALID; + } else { + submit->bos[i].iova = iova; + /* iova changed, so address in cmdstream is not valid: */ + submit->bos[i].flags &= ~BO_VALID; + submit->valid = false; + } + } + + return ret; +} + static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, struct msm_gem_object **obj, uint32_t *iova, bool *valid) { @@ -349,7 +354,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto out; - ret = submit_validate_objects(submit); + ret = submit_lock_objects(submit); + if (ret) + goto out; + + ret = submit_pin_objects(submit); if (ret) goto out; From ca762a8ae7f453978a4769af9dcd3cb08e45b932 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 15 Mar 2016 17:22:13 -0400 Subject: [PATCH 09/25] drm/msm: introduce msm_fence_context Better encapsulate the per-timeline stuff into fence-context. For now there is just a single fence-context, but eventually we'll also have one per-CRTC to enable fully explicit fencing. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 6 +- drivers/gpu/drm/msm/msm_atomic.c | 9 ++- drivers/gpu/drm/msm/msm_drv.c | 8 ++- drivers/gpu/drm/msm/msm_drv.h | 9 +-- drivers/gpu/drm/msm/msm_fence.c | 87 +++++++++++++++---------- drivers/gpu/drm/msm/msm_fence.h | 21 +++++- drivers/gpu/drm/msm/msm_gem.c | 16 +---- drivers/gpu/drm/msm/msm_gpu.c | 23 ++++--- drivers/gpu/drm/msm/msm_gpu.h | 7 +- 9 files changed, 108 insertions(+), 78 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 4951172ede067..9aab871f4defb 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -121,7 +121,7 @@ void adreno_recover(struct msm_gpu *gpu) gpu->rb->cur = gpu->rb->start; /* reset completed fence seqno, just discard anything pending: */ - adreno_gpu->memptrs->fence = gpu->submitted_fence; + adreno_gpu->memptrs->fence = gpu->fctx->last_fence; adreno_gpu->memptrs->rptr = 0; adreno_gpu->memptrs->wptr = 0; @@ -254,7 +254,7 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) adreno_gpu->rev.patchid); seq_printf(m, "fence: %d/%d\n", adreno_gpu->memptrs->fence, - gpu->submitted_fence); + gpu->fctx->last_fence); seq_printf(m, "rptr: %d\n", get_rptr(adreno_gpu)); seq_printf(m, "wptr: %d\n", adreno_gpu->memptrs->wptr); seq_printf(m, "rb wptr: %d\n", get_wptr(gpu->rb)); @@ -295,7 +295,7 @@ void adreno_dump_info(struct msm_gpu *gpu) adreno_gpu->rev.patchid); printk("fence: %d/%d\n", adreno_gpu->memptrs->fence, - gpu->submitted_fence); + gpu->fctx->last_fence); printk("rptr: %d\n", get_rptr(adreno_gpu)); printk("wptr: %d\n", adreno_gpu->memptrs->wptr); printk("rb wptr: %d\n", get_wptr(gpu->rb)); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index fab0c2d41f66d..a2a3d9f25b7b3 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -18,6 +18,7 @@ #include "msm_drv.h" #include "msm_kms.h" #include "msm_gem.h" +#include "msm_gpu.h" /* temporary */ #include "msm_fence.h" struct msm_commit { @@ -202,6 +203,7 @@ int msm_atomic_check(struct drm_device *dev, int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock) { + struct msm_drm_private *priv = dev->dev_private; int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; ktime_t timeout; @@ -276,15 +278,16 @@ int msm_atomic_commit(struct drm_device *dev, * current layout. */ - if (nonblock) { - msm_queue_fence_cb(dev, &c->fence_cb, c->fence); + if (nonblock && priv->gpu) { + msm_queue_fence_cb(priv->gpu->fctx, &c->fence_cb, c->fence); return 0; } timeout = ktime_add_ms(ktime_get(), 1000); /* uninterruptible wait */ - msm_wait_fence(dev, c->fence, &timeout, false); + if (priv->gpu) + msm_wait_fence(priv->gpu->fctx, c->fence, &timeout, false); complete_commit(c); diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index d4a1a11ccc432..2b859f38772a0 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -339,11 +339,9 @@ static int msm_load(struct drm_device *dev, unsigned long flags) dev->dev_private = priv; priv->wq = alloc_ordered_workqueue("msm", 0); - init_waitqueue_head(&priv->fence_event); init_waitqueue_head(&priv->pending_crtcs_event); 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); @@ -647,6 +645,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, struct drm_file *file) { + struct msm_drm_private *priv = dev->dev_private; struct drm_msm_wait_fence *args = data; ktime_t timeout = to_ktime(args->timeout); @@ -655,7 +654,10 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, return -EINVAL; } - return msm_wait_fence(dev, args->fence, &timeout, true); + if (!priv->gpu) + return 0; + + return msm_wait_fence(priv->gpu->fctx, args->fence, &timeout, true); } static const struct drm_ioctl_desc msm_ioctls[] = { diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index af007ac8c7339..6c3f67bc1bb76 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -49,6 +49,7 @@ struct msm_mmu; struct msm_rd_state; struct msm_perf_state; struct msm_gem_submit; +struct msm_fence_context; struct msm_fence_cb; #define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */ @@ -101,9 +102,6 @@ struct msm_drm_private { struct drm_fb_helper *fbdev; - uint32_t next_fence, completed_fence; - wait_queue_head_t fence_event; - struct msm_rd_state *rd; struct msm_perf_state *perf; @@ -112,9 +110,6 @@ struct msm_drm_private { struct workqueue_struct *wq; - /* callbacks deferred until bo is inactive: */ - struct list_head fence_cbs; - /* crtcs pending async atomic updates: */ uint32_t pending_crtcs; wait_queue_head_t pending_crtcs_event; @@ -194,8 +189,6 @@ int msm_gem_prime_pin(struct drm_gem_object *obj); void msm_gem_prime_unpin(struct drm_gem_object *obj); void *msm_gem_vaddr_locked(struct drm_gem_object *obj); void *msm_gem_vaddr(struct drm_gem_object *obj); -int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, - struct msm_fence_cb *cb); void msm_gem_move_to_active(struct drm_gem_object *obj, struct msm_gpu *gpu, bool write, uint32_t fence); void msm_gem_move_to_inactive(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index 002eecb3934e4..f0ed6a680653c 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -15,49 +15,68 @@ * this program. If not, see . */ +#include + #include "msm_drv.h" #include "msm_fence.h" -#include "msm_gpu.h" -static inline bool fence_completed(struct drm_device *dev, uint32_t fence) + +struct msm_fence_context * +msm_fence_context_alloc(struct drm_device *dev, const char *name) { - struct msm_drm_private *priv = dev->dev_private; - return (int32_t)(priv->completed_fence - fence) >= 0; + struct msm_fence_context *fctx; + + fctx = kzalloc(sizeof(*fctx), GFP_KERNEL); + if (!fctx) + return ERR_PTR(-ENOMEM); + + fctx->dev = dev; + fctx->name = name; + init_waitqueue_head(&fctx->event); + INIT_LIST_HEAD(&fctx->fence_cbs); + + return fctx; } -int msm_wait_fence(struct drm_device *dev, uint32_t fence, - ktime_t *timeout , bool interruptible) +void msm_fence_context_free(struct msm_fence_context *fctx) { - struct msm_drm_private *priv = dev->dev_private; - int ret; + kfree(fctx); +} + +static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fence) +{ + return (int32_t)(fctx->completed_fence - fence) >= 0; +} - if (!priv->gpu) - return 0; +int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, + ktime_t *timeout, bool interruptible) +{ + int ret; - if (fence > priv->gpu->submitted_fence) { - DRM_ERROR("waiting on invalid fence: %u (of %u)\n", - fence, priv->gpu->submitted_fence); + if (fence > fctx->last_fence) { + DRM_ERROR("%s: waiting on invalid fence: %u (of %u)\n", + fctx->name, fence, fctx->last_fence); return -EINVAL; } if (!timeout) { /* no-wait: */ - ret = fence_completed(dev, fence) ? 0 : -EBUSY; + ret = fence_completed(fctx, fence) ? 0 : -EBUSY; } else { unsigned long remaining_jiffies = timeout_to_jiffies(timeout); if (interruptible) - ret = wait_event_interruptible_timeout(priv->fence_event, - fence_completed(dev, fence), + ret = wait_event_interruptible_timeout(fctx->event, + fence_completed(fctx, fence), remaining_jiffies); else - ret = wait_event_timeout(priv->fence_event, - fence_completed(dev, fence), + ret = wait_event_timeout(fctx->event, + fence_completed(fctx, fence), remaining_jiffies); if (ret == 0) { DBG("timeout waiting for fence: %u (completed: %u)", - fence, priv->completed_fence); + fence, fctx->completed_fence); ret = -ETIMEDOUT; } else if (ret != -ERESTARTSYS) { ret = 0; @@ -67,50 +86,50 @@ int msm_wait_fence(struct drm_device *dev, uint32_t fence, return ret; } -int msm_queue_fence_cb(struct drm_device *dev, +int msm_queue_fence_cb(struct msm_fence_context *fctx, struct msm_fence_cb *cb, uint32_t fence) { - struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_private *priv = fctx->dev->dev_private; int ret = 0; - mutex_lock(&dev->struct_mutex); + mutex_lock(&fctx->dev->struct_mutex); if (!list_empty(&cb->work.entry)) { ret = -EINVAL; - } else if (fence > priv->completed_fence) { + } else if (fence > fctx->completed_fence) { cb->fence = fence; - list_add_tail(&cb->work.entry, &priv->fence_cbs); + list_add_tail(&cb->work.entry, &fctx->fence_cbs); } else { queue_work(priv->wq, &cb->work); } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&fctx->dev->struct_mutex); return ret; } /* called from workqueue */ -void msm_update_fence(struct drm_device *dev, uint32_t fence) +void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) { - struct msm_drm_private *priv = dev->dev_private; + struct msm_drm_private *priv = fctx->dev->dev_private; - mutex_lock(&dev->struct_mutex); - priv->completed_fence = max(fence, priv->completed_fence); + mutex_lock(&fctx->dev->struct_mutex); + fctx->completed_fence = max(fence, fctx->completed_fence); - while (!list_empty(&priv->fence_cbs)) { + while (!list_empty(&fctx->fence_cbs)) { struct msm_fence_cb *cb; - cb = list_first_entry(&priv->fence_cbs, + cb = list_first_entry(&fctx->fence_cbs, struct msm_fence_cb, work.entry); - if (cb->fence > priv->completed_fence) + if (cb->fence > fctx->completed_fence) break; list_del_init(&cb->work.entry); queue_work(priv->wq, &cb->work); } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&fctx->dev->struct_mutex); - wake_up_all(&priv->fence_event); + wake_up_all(&fctx->event); } void __msm_fence_worker(struct work_struct *work) diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 6ddb81c2c3666..3ed20981fc056 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -20,6 +20,21 @@ #include "msm_drv.h" +struct msm_fence_context { + struct drm_device *dev; + const char *name; + /* last_fence == completed_fence --> no pending work */ + uint32_t last_fence; /* last assigned fence */ + uint32_t completed_fence; /* last completed fence */ + wait_queue_head_t event; + /* callbacks deferred until bo is inactive: */ + struct list_head fence_cbs; +}; + +struct msm_fence_context * msm_fence_context_alloc(struct drm_device *dev, + const char *name); +void msm_fence_context_free(struct msm_fence_context *fctx); + /* callback from wq once fence has passed: */ struct msm_fence_cb { struct work_struct work; @@ -34,10 +49,10 @@ void __msm_fence_worker(struct work_struct *work); (_cb)->func = _func; \ } while (0) -int msm_wait_fence(struct drm_device *dev, uint32_t fence, +int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, ktime_t *timeout, bool interruptible); -int msm_queue_fence_cb(struct drm_device *dev, +int msm_queue_fence_cb(struct msm_fence_context *fctx, struct msm_fence_cb *cb, uint32_t fence); -void msm_update_fence(struct drm_device *dev, uint32_t fence); +void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence); #endif diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 09e2190a09ed1..80aba76f7a4d0 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -411,18 +411,6 @@ void *msm_gem_vaddr(struct drm_gem_object *obj) return ret; } -/* setup callback for when bo is no longer busy.. - * TODO probably want to differentiate read vs write.. - */ -int msm_gem_queue_inactive_cb(struct drm_gem_object *obj, - struct msm_fence_cb *cb) -{ - struct msm_gem_object *msm_obj = to_msm_bo(obj); - uint32_t fence = msm_gem_fence(msm_obj, - MSM_PREP_READ | MSM_PREP_WRITE); - return msm_queue_fence_cb(obj->dev, cb, fence); -} - void msm_gem_move_to_active(struct drm_gem_object *obj, struct msm_gpu *gpu, bool write, uint32_t fence) { @@ -454,6 +442,7 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj) int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) { struct drm_device *dev = obj->dev; + struct msm_drm_private *priv = dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); int ret = 0; @@ -463,7 +452,8 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) if (op & MSM_PREP_NOSYNC) timeout = NULL; - ret = msm_wait_fence(dev, fence, timeout, true); + if (priv->gpu) + ret = msm_wait_fence(priv->gpu->fctx, fence, timeout, true); } /* TODO cache maintenance */ diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 80efe56b80f8f..8f0b29548cfc8 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -313,7 +313,7 @@ static void hangcheck_handler(unsigned long data) if (fence != gpu->hangcheck_fence) { /* some progress has been made.. ya! */ gpu->hangcheck_fence = fence; - } else if (fence < gpu->submitted_fence) { + } else if (fence < gpu->fctx->last_fence) { /* no progress and not done.. hung! */ gpu->hangcheck_fence = fence; dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n", @@ -321,12 +321,12 @@ static void hangcheck_handler(unsigned long data) dev_err(dev->dev, "%s: completed fence: %u\n", gpu->name, fence); dev_err(dev->dev, "%s: submitted fence: %u\n", - gpu->name, gpu->submitted_fence); + gpu->name, gpu->fctx->last_fence); queue_work(priv->wq, &gpu->recover_work); } /* if still more pending work, reset the hangcheck timer: */ - if (gpu->submitted_fence > gpu->hangcheck_fence) + if (gpu->fctx->last_fence > gpu->hangcheck_fence) hangcheck_timer_reset(gpu); /* workaround for missing irq: */ @@ -474,7 +474,7 @@ static void retire_worker(struct work_struct *work) struct drm_device *dev = gpu->dev; uint32_t fence = gpu->funcs->last_fence(gpu); - msm_update_fence(gpu->dev, fence); + msm_update_fence(gpu->fctx, fence); mutex_lock(&dev->struct_mutex); retire_submits(gpu, fence); @@ -502,9 +502,7 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - submit->fence = ++priv->next_fence; - - gpu->submitted_fence = submit->fence; + submit->fence = ++gpu->fctx->last_fence; inactive_cancel(gpu); @@ -512,8 +510,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_rd_dump_submit(submit); - gpu->submitted_fence = submit->fence; - update_sw_cntrs(gpu); for (i = 0; i < submit->nr_bos; i++) { @@ -574,6 +570,12 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, gpu->funcs = funcs; gpu->name = name; gpu->inactive = true; + gpu->fctx = msm_fence_context_alloc(drm, name); + if (IS_ERR(gpu->fctx)) { + ret = PTR_ERR(gpu->fctx); + gpu->fctx = NULL; + goto fail; + } INIT_LIST_HEAD(&gpu->active_list); INIT_WORK(&gpu->retire_work, retire_worker); @@ -694,4 +696,7 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) if (gpu->mmu) gpu->mmu->funcs->destroy(gpu->mmu); + + if (gpu->fctx) + msm_fence_context_free(gpu->fctx); } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 2bbe85a3d6f60..025e25b648e7f 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -22,6 +22,7 @@ #include #include "msm_drv.h" +#include "msm_fence.h" #include "msm_ringbuffer.h" struct msm_gem_submit; @@ -77,13 +78,15 @@ struct msm_gpu { const struct msm_gpu_perfcntr *perfcntrs; uint32_t num_perfcntrs; + /* ringbuffer: */ struct msm_ringbuffer *rb; uint32_t rb_iova; /* list of GEM active objects: */ struct list_head active_list; - uint32_t submitted_fence; + /* fencing: */ + struct msm_fence_context *fctx; /* is gpu powered/active? */ int active_cnt; @@ -125,7 +128,7 @@ struct msm_gpu { static inline bool msm_gpu_active(struct msm_gpu *gpu) { - return gpu->submitted_fence > gpu->funcs->last_fence(gpu); + return gpu->fctx->last_fence > gpu->funcs->last_fence(gpu); } /* Perf-Counters: From ba00c3f2f0c84456ffe9d548823ff4fb8e4e7ed4 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Wed, 16 Mar 2016 18:18:17 -0400 Subject: [PATCH 10/25] drm/msm: remove fence_cbs This was only used for atomic commit these days. So instead just give atomic it's own work-queue where we can do a block on each bo in turn. Simplifies things a whole bunch and makes the 'struct fence' conversion easier. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_atomic.c | 77 +++++++++++++------------------- drivers/gpu/drm/msm/msm_drv.c | 4 ++ drivers/gpu/drm/msm/msm_drv.h | 5 ++- drivers/gpu/drm/msm/msm_fence.c | 43 ------------------ drivers/gpu/drm/msm/msm_fence.h | 16 ------- drivers/gpu/drm/msm/msm_gem.c | 9 +++- 6 files changed, 47 insertions(+), 107 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index a2a3d9f25b7b3..6ac7192d0ad65 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -18,18 +18,16 @@ #include "msm_drv.h" #include "msm_kms.h" #include "msm_gem.h" -#include "msm_gpu.h" /* temporary */ #include "msm_fence.h" struct msm_commit { struct drm_device *dev; struct drm_atomic_state *state; - uint32_t fence; - struct msm_fence_cb fence_cb; + struct work_struct work; uint32_t crtc_mask; }; -static void fence_cb(struct msm_fence_cb *cb); +static void commit_worker(struct work_struct *work); /* block until specified crtcs are no longer pending update, and * atomically mark them as pending update @@ -71,11 +69,7 @@ static struct msm_commit *commit_init(struct drm_atomic_state *state) c->dev = state->dev; c->state = state; - /* TODO we might need a way to indicate to run the cb on a - * different wq so wait_for_vblanks() doesn't block retiring - * bo's.. - */ - INIT_FENCE_CB(&c->fence_cb, fence_cb); + INIT_WORK(&c->work, commit_worker); return c; } @@ -113,16 +107,39 @@ static void msm_atomic_wait_for_commit_done(struct drm_device *dev, } } +static void wait_fences(struct msm_commit *c, bool async) +{ + int nplanes = c->dev->mode_config.num_total_plane; + ktime_t timeout = ktime_add_ms(ktime_get(), 1000); + int i; + + for (i = 0; i < nplanes; i++) { + struct drm_plane *plane = c->state->planes[i]; + struct drm_plane_state *new_state = c->state->plane_states[i]; + + if (!plane) + continue; + + if ((plane->state->fb != new_state->fb) && new_state->fb) { + struct drm_gem_object *obj = + msm_framebuffer_bo(new_state->fb, 0); + msm_gem_cpu_sync(obj, MSM_PREP_READ, &timeout); + } + } +} + /* The (potentially) asynchronous part of the commit. At this point * nothing can fail short of armageddon. */ -static void complete_commit(struct msm_commit *c) +static void complete_commit(struct msm_commit *c, bool async) { struct drm_atomic_state *state = c->state; struct drm_device *dev = state->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; + wait_fences(c, async); + kms->funcs->prepare_commit(kms, state); drm_atomic_helper_commit_modeset_disables(dev, state); @@ -155,17 +172,9 @@ static void complete_commit(struct msm_commit *c) commit_destroy(c); } -static void fence_cb(struct msm_fence_cb *cb) +static void commit_worker(struct work_struct *work) { - struct msm_commit *c = - container_of(cb, struct msm_commit, fence_cb); - complete_commit(c); -} - -static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb) -{ - struct drm_gem_object *obj = msm_framebuffer_bo(fb, 0); - c->fence = max(c->fence, msm_gem_fence(to_msm_bo(obj), MSM_PREP_READ)); + complete_commit(container_of(work, struct msm_commit, work), true); } int msm_atomic_check(struct drm_device *dev, @@ -204,9 +213,7 @@ int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock) { struct msm_drm_private *priv = dev->dev_private; - int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; - ktime_t timeout; struct msm_commit *c; int i, ret; @@ -230,20 +237,6 @@ int msm_atomic_commit(struct drm_device *dev, c->crtc_mask |= (1 << drm_crtc_index(crtc)); } - /* - * Figure out what fence to wait for: - */ - for (i = 0; i < nplanes; i++) { - struct drm_plane *plane = state->planes[i]; - struct drm_plane_state *new_state = state->plane_states[i]; - - if (!plane) - continue; - - if ((plane->state->fb != new_state->fb) && new_state->fb) - add_fb(c, new_state->fb); - } - /* * Wait for pending updates on any of the same crtc's and then * mark our set of crtc's as busy: @@ -278,18 +271,12 @@ int msm_atomic_commit(struct drm_device *dev, * current layout. */ - if (nonblock && priv->gpu) { - msm_queue_fence_cb(priv->gpu->fctx, &c->fence_cb, c->fence); + if (nonblock) { + queue_work(priv->atomic_wq, &c->work); return 0; } - timeout = ktime_add_ms(ktime_get(), 1000); - - /* uninterruptible wait */ - if (priv->gpu) - msm_wait_fence(priv->gpu->fctx, c->fence, &timeout, false); - - complete_commit(c); + complete_commit(c, false); return 0; diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 2b859f38772a0..745793991ba67 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -213,6 +213,9 @@ static int msm_unload(struct drm_device *dev) flush_workqueue(priv->wq); destroy_workqueue(priv->wq); + flush_workqueue(priv->atomic_wq); + destroy_workqueue(priv->atomic_wq); + if (kms) { pm_runtime_disable(dev->dev); kms->funcs->destroy(kms); @@ -339,6 +342,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) dev->dev_private = priv; priv->wq = alloc_ordered_workqueue("msm", 0); + priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); init_waitqueue_head(&priv->pending_crtcs_event); INIT_LIST_HEAD(&priv->inactive_list); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 6c3f67bc1bb76..7124c7f262ec6 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -109,6 +109,7 @@ struct msm_drm_private { struct list_head inactive_list; struct workqueue_struct *wq; + struct workqueue_struct *atomic_wq; /* crtcs pending async atomic updates: */ uint32_t pending_crtcs; @@ -192,8 +193,8 @@ void *msm_gem_vaddr(struct drm_gem_object *obj); void msm_gem_move_to_active(struct drm_gem_object *obj, struct msm_gpu *gpu, bool write, uint32_t fence); void msm_gem_move_to_inactive(struct drm_gem_object *obj); -int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, - ktime_t *timeout); +int msm_gem_cpu_sync(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); int msm_gem_cpu_fini(struct drm_gem_object *obj); void msm_gem_free_object(struct drm_gem_object *obj); int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file, diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index f0ed6a680653c..088610ca80ca0 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -33,7 +33,6 @@ msm_fence_context_alloc(struct drm_device *dev, const char *name) fctx->dev = dev; fctx->name = name; init_waitqueue_head(&fctx->event); - INIT_LIST_HEAD(&fctx->fence_cbs); return fctx; } @@ -86,54 +85,12 @@ int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, return ret; } -int msm_queue_fence_cb(struct msm_fence_context *fctx, - struct msm_fence_cb *cb, uint32_t fence) -{ - struct msm_drm_private *priv = fctx->dev->dev_private; - int ret = 0; - - mutex_lock(&fctx->dev->struct_mutex); - if (!list_empty(&cb->work.entry)) { - ret = -EINVAL; - } else if (fence > fctx->completed_fence) { - cb->fence = fence; - list_add_tail(&cb->work.entry, &fctx->fence_cbs); - } else { - queue_work(priv->wq, &cb->work); - } - mutex_unlock(&fctx->dev->struct_mutex); - - return ret; -} - /* called from workqueue */ void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) { - struct msm_drm_private *priv = fctx->dev->dev_private; - mutex_lock(&fctx->dev->struct_mutex); fctx->completed_fence = max(fence, fctx->completed_fence); - - while (!list_empty(&fctx->fence_cbs)) { - struct msm_fence_cb *cb; - - cb = list_first_entry(&fctx->fence_cbs, - struct msm_fence_cb, work.entry); - - if (cb->fence > fctx->completed_fence) - break; - - list_del_init(&cb->work.entry); - queue_work(priv->wq, &cb->work); - } - mutex_unlock(&fctx->dev->struct_mutex); wake_up_all(&fctx->event); } - -void __msm_fence_worker(struct work_struct *work) -{ - struct msm_fence_cb *cb = container_of(work, struct msm_fence_cb, work); - cb->func(cb); -} diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 3ed20981fc056..2820781d974a3 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -27,28 +27,12 @@ struct msm_fence_context { uint32_t last_fence; /* last assigned fence */ uint32_t completed_fence; /* last completed fence */ wait_queue_head_t event; - /* callbacks deferred until bo is inactive: */ - struct list_head fence_cbs; }; struct msm_fence_context * msm_fence_context_alloc(struct drm_device *dev, const char *name); void msm_fence_context_free(struct msm_fence_context *fctx); -/* callback from wq once fence has passed: */ -struct msm_fence_cb { - struct work_struct work; - uint32_t fence; - void (*func)(struct msm_fence_cb *cb); -}; - -void __msm_fence_worker(struct work_struct *work); - -#define INIT_FENCE_CB(_cb, _func) do { \ - INIT_WORK(&(_cb)->work, __msm_fence_worker); \ - (_cb)->func = _func; \ - } while (0) - int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, ktime_t *timeout, bool interruptible); int msm_queue_fence_cb(struct msm_fence_context *fctx, diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 80aba76f7a4d0..9080ed13998af 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -439,7 +439,7 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj) list_add_tail(&msm_obj->mm_list, &priv->inactive_list); } -int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) +int msm_gem_cpu_sync(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) { struct drm_device *dev = obj->dev; struct msm_drm_private *priv = dev->dev_private; @@ -456,6 +456,13 @@ int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) ret = msm_wait_fence(priv->gpu->fctx, fence, timeout, true); } + return ret; +} + +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) +{ + int ret = msm_gem_cpu_sync(obj, op, timeout); + /* TODO cache maintenance */ return ret; From b6295f9a38fc3f7d59ec0caa45aa803461c6cea5 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 15 Mar 2016 18:26:28 -0400 Subject: [PATCH 11/25] drm/msm: 'struct fence' conversion Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 4 +- drivers/gpu/drm/msm/msm_atomic.c | 42 ++++---- drivers/gpu/drm/msm/msm_drv.h | 5 +- drivers/gpu/drm/msm/msm_fence.c | 71 +++++++++++++- drivers/gpu/drm/msm/msm_fence.h | 4 + drivers/gpu/drm/msm/msm_gem.c | 124 ++++++++++++++++++------ drivers/gpu/drm/msm/msm_gem.h | 16 +-- drivers/gpu/drm/msm/msm_gem_submit.c | 22 ++++- drivers/gpu/drm/msm/msm_gpu.c | 27 ++++-- drivers/gpu/drm/msm/msm_rd.c | 2 +- 10 files changed, 233 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 9aab871f4defb..95aed377b933b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -168,7 +168,7 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, OUT_PKT2(ring); OUT_PKT0(ring, REG_AXXX_CP_SCRATCH_REG2, 1); - OUT_RING(ring, submit->fence); + OUT_RING(ring, submit->fence->seqno); if (adreno_is_a3xx(adreno_gpu) || adreno_is_a4xx(adreno_gpu)) { /* Flush HLSQ lazy updates to make sure there is nothing @@ -185,7 +185,7 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, OUT_PKT3(ring, CP_EVENT_WRITE, 3); OUT_RING(ring, CACHE_FLUSH_TS); OUT_RING(ring, rbmemptr(adreno_gpu, fence)); - OUT_RING(ring, submit->fence); + OUT_RING(ring, submit->fence->seqno); /* we could maybe be clever and only CP_COND_EXEC the interrupt: */ OUT_PKT3(ring, CP_INTERRUPT, 1); diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 6ac7192d0ad65..e3892c263f279 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -107,27 +107,6 @@ static void msm_atomic_wait_for_commit_done(struct drm_device *dev, } } -static void wait_fences(struct msm_commit *c, bool async) -{ - int nplanes = c->dev->mode_config.num_total_plane; - ktime_t timeout = ktime_add_ms(ktime_get(), 1000); - int i; - - for (i = 0; i < nplanes; i++) { - struct drm_plane *plane = c->state->planes[i]; - struct drm_plane_state *new_state = c->state->plane_states[i]; - - if (!plane) - continue; - - if ((plane->state->fb != new_state->fb) && new_state->fb) { - struct drm_gem_object *obj = - msm_framebuffer_bo(new_state->fb, 0); - msm_gem_cpu_sync(obj, MSM_PREP_READ, &timeout); - } - } -} - /* The (potentially) asynchronous part of the commit. At this point * nothing can fail short of armageddon. */ @@ -138,7 +117,7 @@ static void complete_commit(struct msm_commit *c, bool async) struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; - wait_fences(c, async); + drm_atomic_helper_wait_for_fences(dev, state); kms->funcs->prepare_commit(kms, state); @@ -213,6 +192,7 @@ int msm_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool nonblock) { struct msm_drm_private *priv = dev->dev_private; + int nplanes = dev->mode_config.num_total_plane; int ncrtcs = dev->mode_config.num_crtc; struct msm_commit *c; int i, ret; @@ -237,6 +217,24 @@ int msm_atomic_commit(struct drm_device *dev, c->crtc_mask |= (1 << drm_crtc_index(crtc)); } + /* + * Figure out what fence to wait for: + */ + for (i = 0; i < nplanes; i++) { + struct drm_plane *plane = state->planes[i]; + struct drm_plane_state *new_state = state->plane_states[i]; + + if (!plane) + continue; + + if ((plane->state->fb != new_state->fb) && new_state->fb) { + struct drm_gem_object *obj = msm_framebuffer_bo(new_state->fb, 0); + struct msm_gem_object *msm_obj = to_msm_bo(obj); + + new_state->fence = reservation_object_get_excl_rcu(msm_obj->resv); + } + } + /* * Wait for pending updates on any of the same crtc's and then * mark our set of crtc's as busy: diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 7124c7f262ec6..4114a40e4a09a 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -190,10 +190,11 @@ int msm_gem_prime_pin(struct drm_gem_object *obj); void msm_gem_prime_unpin(struct drm_gem_object *obj); void *msm_gem_vaddr_locked(struct drm_gem_object *obj); void *msm_gem_vaddr(struct drm_gem_object *obj); +int msm_gem_sync_object(struct drm_gem_object *obj, + struct msm_fence_context *fctx, bool exclusive); void msm_gem_move_to_active(struct drm_gem_object *obj, - struct msm_gpu *gpu, bool write, uint32_t fence); + struct msm_gpu *gpu, bool exclusive, struct fence *fence); void msm_gem_move_to_inactive(struct drm_gem_object *obj); -int msm_gem_cpu_sync(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout); int msm_gem_cpu_fini(struct drm_gem_object *obj); void msm_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/msm/msm_fence.c b/drivers/gpu/drm/msm/msm_fence.c index 088610ca80ca0..a9b9b1c95a2eb 100644 --- a/drivers/gpu/drm/msm/msm_fence.c +++ b/drivers/gpu/drm/msm/msm_fence.c @@ -32,7 +32,9 @@ msm_fence_context_alloc(struct drm_device *dev, const char *name) fctx->dev = dev; fctx->name = name; + fctx->context = fence_context_alloc(1); init_waitqueue_head(&fctx->event); + spin_lock_init(&fctx->spinlock); return fctx; } @@ -47,6 +49,7 @@ static inline bool fence_completed(struct msm_fence_context *fctx, uint32_t fenc return (int32_t)(fctx->completed_fence - fence) >= 0; } +/* legacy path for WAIT_FENCE ioctl: */ int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, ktime_t *timeout, bool interruptible) { @@ -88,9 +91,73 @@ int msm_wait_fence(struct msm_fence_context *fctx, uint32_t fence, /* called from workqueue */ void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence) { - mutex_lock(&fctx->dev->struct_mutex); + spin_lock(&fctx->spinlock); fctx->completed_fence = max(fence, fctx->completed_fence); - mutex_unlock(&fctx->dev->struct_mutex); + spin_unlock(&fctx->spinlock); wake_up_all(&fctx->event); } + +struct msm_fence { + struct msm_fence_context *fctx; + struct fence base; +}; + +static inline struct msm_fence *to_msm_fence(struct fence *fence) +{ + return container_of(fence, struct msm_fence, base); +} + +static const char *msm_fence_get_driver_name(struct fence *fence) +{ + return "msm"; +} + +static const char *msm_fence_get_timeline_name(struct fence *fence) +{ + struct msm_fence *f = to_msm_fence(fence); + return f->fctx->name; +} + +static bool msm_fence_enable_signaling(struct fence *fence) +{ + return true; +} + +static bool msm_fence_signaled(struct fence *fence) +{ + struct msm_fence *f = to_msm_fence(fence); + return fence_completed(f->fctx, f->base.seqno); +} + +static void msm_fence_release(struct fence *fence) +{ + struct msm_fence *f = to_msm_fence(fence); + kfree_rcu(f, base.rcu); +} + +static const struct fence_ops msm_fence_ops = { + .get_driver_name = msm_fence_get_driver_name, + .get_timeline_name = msm_fence_get_timeline_name, + .enable_signaling = msm_fence_enable_signaling, + .signaled = msm_fence_signaled, + .wait = fence_default_wait, + .release = msm_fence_release, +}; + +struct fence * +msm_fence_alloc(struct msm_fence_context *fctx) +{ + struct msm_fence *f; + + f = kzalloc(sizeof(*f), GFP_KERNEL); + if (!f) + return ERR_PTR(-ENOMEM); + + f->fctx = fctx; + + fence_init(&f->base, &msm_fence_ops, &fctx->spinlock, + fctx->context, ++fctx->last_fence); + + return &f->base; +} diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 2820781d974a3..ceb5b3d314b40 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -23,10 +23,12 @@ struct msm_fence_context { struct drm_device *dev; const char *name; + unsigned context; /* last_fence == completed_fence --> no pending work */ uint32_t last_fence; /* last assigned fence */ uint32_t completed_fence; /* last completed fence */ wait_queue_head_t event; + spinlock_t spinlock; }; struct msm_fence_context * msm_fence_context_alloc(struct drm_device *dev, @@ -39,4 +41,6 @@ int msm_queue_fence_cb(struct msm_fence_context *fctx, struct msm_fence_cb *cb, uint32_t fence); void msm_update_fence(struct msm_fence_context *fctx, uint32_t fence); +struct fence * msm_fence_alloc(struct msm_fence_context *fctx); + #endif diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 9080ed13998af..9bbe1c5e71513 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -411,15 +411,62 @@ void *msm_gem_vaddr(struct drm_gem_object *obj) return ret; } +/* must be called before _move_to_active().. */ +int msm_gem_sync_object(struct drm_gem_object *obj, + struct msm_fence_context *fctx, bool exclusive) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct reservation_object_list *fobj; + struct fence *fence; + int i, ret; + + if (!exclusive) { + /* NOTE: _reserve_shared() must happen before _add_shared_fence(), + * which makes this a slightly strange place to call it. OTOH this + * is a convenient can-fail point to hook it in. (And similar to + * how etnaviv and nouveau handle this.) + */ + ret = reservation_object_reserve_shared(msm_obj->resv); + if (ret) + return ret; + } + + fobj = reservation_object_get_list(msm_obj->resv); + if (!fobj || (fobj->shared_count == 0)) { + fence = reservation_object_get_excl(msm_obj->resv); + /* don't need to wait on our own fences, since ring is fifo */ + if (fence && (fence->context != fctx->context)) { + ret = fence_wait(fence, true); + if (ret) + return ret; + } + } + + if (!exclusive || !fobj) + return 0; + + for (i = 0; i < fobj->shared_count; i++) { + fence = rcu_dereference_protected(fobj->shared[i], + reservation_object_held(msm_obj->resv)); + if (fence->context != fctx->context) { + ret = fence_wait(fence, true); + if (ret) + return ret; + } + } + + return 0; +} + void msm_gem_move_to_active(struct drm_gem_object *obj, - struct msm_gpu *gpu, bool write, uint32_t fence) + struct msm_gpu *gpu, bool exclusive, struct fence *fence) { struct msm_gem_object *msm_obj = to_msm_bo(obj); msm_obj->gpu = gpu; - if (write) - msm_obj->write_fence = fence; + if (exclusive) + reservation_object_add_excl_fence(msm_obj->resv, fence); else - msm_obj->read_fence = fence; + reservation_object_add_shared_fence(msm_obj->resv, fence); list_del_init(&msm_obj->mm_list); list_add_tail(&msm_obj->mm_list, &gpu->active_list); } @@ -433,39 +480,30 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj) WARN_ON(!mutex_is_locked(&dev->struct_mutex)); msm_obj->gpu = NULL; - msm_obj->read_fence = 0; - msm_obj->write_fence = 0; list_del_init(&msm_obj->mm_list); list_add_tail(&msm_obj->mm_list, &priv->inactive_list); } -int msm_gem_cpu_sync(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) +int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) { - struct drm_device *dev = obj->dev; - struct msm_drm_private *priv = dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); - int ret = 0; - - if (is_active(msm_obj)) { - uint32_t fence = msm_gem_fence(msm_obj, op); + bool write = !!(op & MSM_PREP_WRITE); - if (op & MSM_PREP_NOSYNC) - timeout = NULL; + if (op & MSM_PREP_NOSYNC) { + if (!reservation_object_test_signaled_rcu(msm_obj->resv, write)) + return -EBUSY; + } else { + int ret; - if (priv->gpu) - ret = msm_wait_fence(priv->gpu->fctx, fence, timeout, true); + ret = reservation_object_wait_timeout_rcu(msm_obj->resv, write, + true, timeout_to_jiffies(timeout)); + if (ret <= 0) + return ret == 0 ? -ETIMEDOUT : ret; } - return ret; -} - -int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout) -{ - int ret = msm_gem_cpu_sync(obj, op, timeout); - /* TODO cache maintenance */ - return ret; + return 0; } int msm_gem_cpu_fini(struct drm_gem_object *obj) @@ -475,18 +513,46 @@ int msm_gem_cpu_fini(struct drm_gem_object *obj) } #ifdef CONFIG_DEBUG_FS +static void describe_fence(struct fence *fence, const char *type, + struct seq_file *m) +{ + if (!fence_is_signaled(fence)) + seq_printf(m, "\t%9s: %s %s seq %u\n", type, + fence->ops->get_driver_name(fence), + fence->ops->get_timeline_name(fence), + fence->seqno); +} + void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { - struct drm_device *dev = obj->dev; struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct reservation_object *robj = msm_obj->resv; + struct reservation_object_list *fobj; + struct fence *fence; uint64_t off = drm_vma_node_start(&obj->vma_node); - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %zu\n", + WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); + + seq_printf(m, "%08x: %c %2d (%2d) %08llx %p %zu\n", msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', - msm_obj->read_fence, msm_obj->write_fence, obj->name, obj->refcount.refcount.counter, off, msm_obj->vaddr, obj->size); + + rcu_read_lock(); + fobj = rcu_dereference(robj->fence); + if (fobj) { + unsigned int i, shared_count = fobj->shared_count; + + for (i = 0; i < shared_count; i++) { + fence = rcu_dereference(fobj->shared[i]); + describe_fence(fence, "Shared", m); + } + } + + fence = rcu_dereference(robj->fence_excl); + if (fence) + describe_fence(fence, "Exclusive", m); + rcu_read_unlock(); } void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index b8904517117d5..2771d155587af 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -39,7 +39,6 @@ struct msm_gem_object { */ struct list_head mm_list; struct msm_gpu *gpu; /* non-null if active */ - uint32_t read_fence, write_fence; /* Transiently in the process of submit ioctl, objects associated * with the submit are on submit->bo_list.. this only lasts for @@ -73,19 +72,6 @@ static inline bool is_active(struct msm_gem_object *msm_obj) return msm_obj->gpu != NULL; } -static inline uint32_t msm_gem_fence(struct msm_gem_object *msm_obj, - uint32_t op) -{ - uint32_t fence = 0; - - if (op & MSM_PREP_READ) - fence = msm_obj->write_fence; - if (op & MSM_PREP_WRITE) - fence = max(fence, msm_obj->read_fence); - - return fence; -} - #define MAX_CMDS 4 /* Created per submit-ioctl, to track bo's and cmdstream bufs, etc, @@ -99,7 +85,7 @@ struct msm_gem_submit { struct list_head node; /* node in gpu submit_list */ struct list_head bo_list; struct ww_acquire_ctx ticket; - uint32_t fence; + struct fence *fence; bool valid; /* true if no cmdstream patching needed */ unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index b231544b3f52d..2661a7cb23c8d 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -184,6 +184,22 @@ static int submit_lock_objects(struct msm_gem_submit *submit) return ret; } +static int submit_fence_sync(struct msm_gem_submit *submit) +{ + int i, ret = 0; + + for (i = 0; i < submit->nr_bos; i++) { + struct msm_gem_object *msm_obj = submit->bos[i].obj; + bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE; + + ret = msm_gem_sync_object(&msm_obj->base, submit->gpu->fctx, write); + if (ret) + break; + } + + return ret; +} + static int submit_pin_objects(struct msm_gem_submit *submit) { int i, ret = 0; @@ -358,6 +374,10 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (ret) goto out; + ret = submit_fence_sync(submit); + if (ret) + goto out; + ret = submit_pin_objects(submit); if (ret) goto out; @@ -424,7 +444,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, ret = msm_gpu_submit(gpu, submit, ctx); - args->fence = submit->fence; + args->fence = submit->fence->seqno; out: submit_cleanup(submit, !!ret); diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 8f0b29548cfc8..f94d01099e198 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -266,22 +266,24 @@ static void inactive_start(struct msm_gpu *gpu) * Hangcheck detection for locked gpu: */ -static void retire_submits(struct msm_gpu *gpu, uint32_t fence); +static void retire_submits(struct msm_gpu *gpu); static void recover_worker(struct work_struct *work) { struct msm_gpu *gpu = container_of(work, struct msm_gpu, recover_work); struct drm_device *dev = gpu->dev; + uint32_t fence = gpu->funcs->last_fence(gpu); dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); + msm_update_fence(gpu->fctx, fence + 1); + mutex_lock(&dev->struct_mutex); if (msm_gpu_active(gpu)) { struct msm_gem_submit *submit; - uint32_t fence = gpu->funcs->last_fence(gpu); /* retire completed submits, plus the one that hung: */ - retire_submits(gpu, fence + 1); + retire_submits(gpu); inactive_cancel(gpu); gpu->funcs->recover(gpu); @@ -444,11 +446,12 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) drm_gem_object_unreference(&msm_obj->base); } + fence_put(submit->fence); list_del(&submit->node); kfree(submit); } -static void retire_submits(struct msm_gpu *gpu, uint32_t fence) +static void retire_submits(struct msm_gpu *gpu) { struct drm_device *dev = gpu->dev; @@ -460,7 +463,7 @@ static void retire_submits(struct msm_gpu *gpu, uint32_t fence) submit = list_first_entry(&gpu->submit_list, struct msm_gem_submit, node); - if (submit->fence <= fence) { + if (fence_is_signaled(submit->fence)) { retire_submit(gpu, submit); } else { break; @@ -477,7 +480,7 @@ static void retire_worker(struct work_struct *work) msm_update_fence(gpu->fctx, fence); mutex_lock(&dev->struct_mutex); - retire_submits(gpu, fence); + retire_submits(gpu); mutex_unlock(&dev->struct_mutex); if (!msm_gpu_active(gpu)) @@ -502,7 +505,12 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - submit->fence = ++gpu->fctx->last_fence; + submit->fence = msm_fence_alloc(gpu->fctx); + if (IS_ERR(submit->fence)) { + ret = PTR_ERR(submit->fence); + submit->fence = NULL; + return ret; + } inactive_cancel(gpu); @@ -526,11 +534,10 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_gem_get_iova_locked(&msm_obj->base, submit->gpu->id, &iova); - if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) - msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); - if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); + else if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) + msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); } ret = gpu->funcs->submit(gpu, submit, ctx); diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 9a78c48817c6a..b48f73ac63896 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -296,7 +296,7 @@ void msm_rd_dump_submit(struct msm_gem_submit *submit) n = snprintf(msg, sizeof(msg), "%.*s/%d: fence=%u", TASK_COMM_LEN, current->comm, task_pid_nr(current), - submit->fence); + submit->fence->seqno); rd_write_section(rd, RD_CMD, msg, ALIGN(n, 4)); From 2755734390c18ca33d9755c9caa2685567563c19 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 17 Mar 2016 10:18:38 -0400 Subject: [PATCH 12/25] drm/msm: fix ->last_fence() after recover It is no longer true that we discard all in-flight submits on recover (these days we only discard the first one that hung). After the first re-submitted batch completes it would overwrite the fence with a correct value, but there would be a window of time which showed all re-submitted batches as already complete. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 95aed377b933b..1d5a714d24a6b 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -120,8 +120,8 @@ void adreno_recover(struct msm_gpu *gpu) /* reset ringbuffer: */ gpu->rb->cur = gpu->rb->start; - /* reset completed fence seqno, just discard anything pending: */ - adreno_gpu->memptrs->fence = gpu->fctx->last_fence; + /* reset completed fence seqno: */ + adreno_gpu->memptrs->fence = gpu->fctx->completed_fence; adreno_gpu->memptrs->rptr = 0; adreno_gpu->memptrs->wptr = 0; From 6979cd54c0667189bb0805c0fcebfef8afc5a191 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 16 Apr 2016 22:41:46 +0200 Subject: [PATCH 13/25] drm: msm: remove unused variable A recent cleanup removed the only user of the 'kms' variable in msm_preclose(), causing a harmless compiler warning: drivers/gpu/drm/msm/msm_drv.c: In function 'msm_preclose': drivers/gpu/drm/msm/msm_drv.c:468:18: error: unused variable 'kms' [-Werror=unused-variable] This removes the variable as well. Signed-off-by: Arnd Bergmann Fixes: 4016260ba47a ("drm/msm: fix bug after preclose removal") Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 745793991ba67..c257cdd346e75 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -469,7 +469,6 @@ static void msm_preclose(struct drm_device *dev, struct drm_file *file) { struct msm_drm_private *priv = dev->dev_private; struct msm_file_private *ctx = file->driver_priv; - struct msm_kms *kms = priv->kms; mutex_lock(&dev->struct_mutex); if (ctx == priv->lastctx) From 30c6bfe8abb51098889c6f894641aff22d2a65d1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 11 Apr 2016 18:23:51 -0500 Subject: [PATCH 14/25] drm/msm/mdp: Add support for more RGBX formats Android needs XBGR8888 format. Add all the missing 32-bpp formats without alpha for completeness. Cc: Archit Taneja Cc: Rob Clark Signed-off-by: Rob Herring Reviewed-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp_format.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c index 1c2caffc97e40..b4a8aa4490eed 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_format.c +++ b/drivers/gpu/drm/msm/mdp/mdp_format.c @@ -105,6 +105,12 @@ static const struct mdp_format formats[] = { MDP_PLANE_INTERLEAVED, CHROMA_FULL, false), FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4, MDP_PLANE_INTERLEAVED, CHROMA_FULL, false), + FMT(XBGR8888, 8, 8, 8, 8, 2, 0, 1, 3, false, true, 4, 4, + MDP_PLANE_INTERLEAVED, CHROMA_FULL, false), + FMT(RGBX8888, 8, 8, 8, 8, 3, 1, 0, 2, false, true, 4, 4, + MDP_PLANE_INTERLEAVED, CHROMA_FULL, false), + FMT(BGRX8888, 8, 8, 8, 8, 3, 2, 0, 1, false, true, 4, 4, + MDP_PLANE_INTERLEAVED, CHROMA_FULL, false), FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3, MDP_PLANE_INTERLEAVED, CHROMA_FULL, false), FMT(BGR888, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 3, 3, From d6c925cada0d92e49c3473bc0a69ea3913fff905 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 28 Apr 2016 18:52:49 +0530 Subject: [PATCH 15/25] drm/msm: Move call to PTR_ERR_OR_ZERO after reassignment Here, a location is reset to NULL before being passed to PTR_ERR. So, PTR_ERR should be called before its argument is reassigned to NULL. Further to simplify things use PTR_ERR_OR_ZERO instead of PTR_ERR and IS_ERR. Problem found using Coccinelle. Signed-off-by: Vaishali Thakkar Reviewed-by: Eric Engestrom [fixed fmt string warning (s/%ld/%d/)] Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/edp/edp_ctrl.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 81200e9be3821..4f7457b14dcce 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -302,21 +302,24 @@ static void edp_clk_disable(struct edp_ctrl *ctrl, u32 clk_mask) static int edp_regulator_init(struct edp_ctrl *ctrl) { struct device *dev = &ctrl->pdev->dev; + int ret; DBG(""); ctrl->vdda_vreg = devm_regulator_get(dev, "vdda"); - if (IS_ERR(ctrl->vdda_vreg)) { - pr_err("%s: Could not get vdda reg, ret = %ld\n", __func__, - PTR_ERR(ctrl->vdda_vreg)); + ret = PTR_ERR_OR_ZERO(ctrl->vdda_vreg); + if (ret) { + pr_err("%s: Could not get vdda reg, ret = %d\n", __func__, + ret); ctrl->vdda_vreg = NULL; - return PTR_ERR(ctrl->vdda_vreg); + return ret; } ctrl->lvl_vreg = devm_regulator_get(dev, "lvl-vdd"); - if (IS_ERR(ctrl->lvl_vreg)) { - pr_err("Could not get lvl-vdd reg, %ld", - PTR_ERR(ctrl->lvl_vreg)); + ret = PTR_ERR_OR_ZERO(ctrl->lvl_vreg); + if (ret) { + pr_err("%s: Could not get lvl-vdd reg, ret = %d\n", __func__, + ret); ctrl->lvl_vreg = NULL; - return PTR_ERR(ctrl->lvl_vreg); + return ret; } return 0; From f377d59729e744122751977eb79b349d2e166095 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 29 Apr 2016 15:19:35 +0530 Subject: [PATCH 16/25] drm/msm/dsi: Fix regulator API abuse The voltage changing code in this driver is broken and should be removed. The driver sets a single, exact voltage on probe. Unless there is a very good reason for this (which should be documented in comments) constraints like this need to be set via the machine constraints, voltage setting in a driver is expected to be used in cases where the voltage varies at runtime. In addition client drivers should almost never be calling regulator_can_set_voltage(), if the device needs to set a voltage it needs to set the voltage and the regulator core will handle the case where the regulator is fixed voltage. If the driver simply skips setting the voltage if it doesn't have permission then it should just not bother in the first place. Originally authored by Mark Brown Remove the min/max voltage data entries per SoC managed by the driver. These aren't needed as we don't try to set voltages any more. Mention in comments the voltages that each regulator expects. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi.h | 2 -- drivers/gpu/drm/msm/dsi/dsi_cfg.c | 34 +++++++++---------- drivers/gpu/drm/msm/dsi/dsi_host.c | 12 ------- drivers/gpu/drm/msm/dsi/phy/dsi_phy.c | 13 ------- drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c | 4 +-- drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c | 4 +-- .../gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c | 2 +- 7 files changed, 22 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi.h b/drivers/gpu/drm/msm/dsi/dsi.h index 749fbb28ec3d1..03f115f532c24 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.h +++ b/drivers/gpu/drm/msm/dsi/dsi.h @@ -41,8 +41,6 @@ enum msm_dsi_phy_type { /* Regulators for DSI devices */ struct dsi_reg_entry { char name[32]; - int min_voltage; - int max_voltage; int enable_load; int disable_load; }; diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index e58e9b91b34d3..93c1ee094eac8 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -22,9 +22,9 @@ static const struct msm_dsi_config apq8064_dsi_cfg = { .reg_cfg = { .num = 3, .regs = { - {"vdda", 1200000, 1200000, 100000, 100}, - {"avdd", 3000000, 3000000, 110000, 100}, - {"vddio", 1800000, 1800000, 100000, 100}, + {"vdda", 100000, 100}, /* 1.2 V */ + {"avdd", 10000, 100}, /* 3.0 V */ + {"vddio", 100000, 100}, /* 1.8 V */ }, }, .bus_clk_names = dsi_v2_bus_clk_names, @@ -40,10 +40,10 @@ static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = { .reg_cfg = { .num = 4, .regs = { - {"gdsc", -1, -1, -1, -1}, - {"vdd", 3000000, 3000000, 150000, 100}, - {"vdda", 1200000, 1200000, 100000, 100}, - {"vddio", 1800000, 1800000, 100000, 100}, + {"gdsc", -1, -1}, + {"vdd", 150000, 100}, /* 3.0 V */ + {"vdda", 100000, 100}, /* 1.2 V */ + {"vddio", 100000, 100}, /* 1.8 V */ }, }, .bus_clk_names = dsi_6g_bus_clk_names, @@ -59,9 +59,9 @@ static const struct msm_dsi_config msm8916_dsi_cfg = { .reg_cfg = { .num = 3, .regs = { - {"gdsc", -1, -1, -1, -1}, - {"vdda", 1200000, 1200000, 100000, 100}, - {"vddio", 1800000, 1800000, 100000, 100}, + {"gdsc", -1, -1}, + {"vdda", 100000, 100}, /* 1.2 V */ + {"vddio", 100000, 100}, /* 1.8 V */ }, }, .bus_clk_names = dsi_8916_bus_clk_names, @@ -73,13 +73,13 @@ static const struct msm_dsi_config msm8994_dsi_cfg = { .reg_cfg = { .num = 7, .regs = { - {"gdsc", -1, -1, -1, -1}, - {"vdda", 1250000, 1250000, 100000, 100}, - {"vddio", 1800000, 1800000, 100000, 100}, - {"vcca", 1000000, 1000000, 10000, 100}, - {"vdd", 1800000, 1800000, 100000, 100}, - {"lab_reg", -1, -1, -1, -1}, - {"ibb_reg", -1, -1, -1, -1}, + {"gdsc", -1, -1}, + {"vdda", 100000, 100}, /* 1.25 V */ + {"vddio", 100000, 100}, /* 1.8 V */ + {"vcca", 10000, 100}, /* 1.0 V */ + {"vdd", 100000, 100}, /* 1.8 V */ + {"lab_reg", -1, -1}, + {"ibb_reg", -1, -1}, }, }, .bus_clk_names = dsi_6g_bus_clk_names, diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 4282ec6bbaafd..a3e47ad83eb39 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -325,18 +325,6 @@ static int dsi_regulator_init(struct msm_dsi_host *msm_host) return ret; } - for (i = 0; i < num; i++) { - if (regulator_can_change_voltage(s[i].consumer)) { - ret = regulator_set_voltage(s[i].consumer, - regs[i].min_voltage, regs[i].max_voltage); - if (ret < 0) { - pr_err("regulator %d set voltage failed, %d\n", - i, ret); - return ret; - } - } - } - return 0; } diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 91a95fb04a4a0..e2f42d8ea2941 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -177,19 +177,6 @@ static int dsi_phy_regulator_init(struct msm_dsi_phy *phy) return ret; } - for (i = 0; i < num; i++) { - if (regulator_can_change_voltage(s[i].consumer)) { - ret = regulator_set_voltage(s[i].consumer, - regs[i].min_voltage, regs[i].max_voltage); - if (ret < 0) { - dev_err(dev, - "regulator %d set voltage failed, %d\n", - i, ret); - return ret; - } - } - } - return 0; } diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c index 2e9ba118d50ac..f4bc11af849a5 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_20nm.c @@ -138,8 +138,8 @@ const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs = { .reg_cfg = { .num = 2, .regs = { - {"vddio", 1800000, 1800000, 100000, 100}, - {"vcca", 1000000, 1000000, 10000, 100}, + {"vddio", 100000, 100}, /* 1.8 V */ + {"vcca", 10000, 100}, /* 1.0 V */ }, }, .ops = { diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c index edf74110ced7b..96d1852af4186 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm.c @@ -138,7 +138,7 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs = { .reg_cfg = { .num = 1, .regs = { - {"vddio", 1800000, 1800000, 100000, 100}, + {"vddio", 100000, 100}, }, }, .ops = { @@ -153,7 +153,7 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs = { .reg_cfg = { .num = 1, .regs = { - {"vddio", 1800000, 1800000, 100000, 100}, + {"vddio", 100000, 100}, /* 1.8 V */ }, }, .ops = { diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c index 197b039ca1f1c..213355a3e767a 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_28nm_8960.c @@ -185,7 +185,7 @@ const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = { .reg_cfg = { .num = 1, .regs = { - {"vddio", 1800000, 1800000, 100000, 100}, + {"vddio", 100000, 100}, /* 1.8 V */ }, }, .ops = { From 1d15c1654f8c438694a8680a4faa6e5f77abd507 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 29 Apr 2016 15:19:36 +0530 Subject: [PATCH 17/25] drm/msm/edp: Drop regulator_set_voltage call The eDP driver tries to set a fixed voltage for one of its regulators(vdda) before enabling it. This shouldn't be done by the driver, the voltage constraints should be specified on the regulator via DT and managed by the regulator core. A driver should call regulator_set_voltage only if it needs to change the voltage during runtime. Drop the regulator_set_voltage call. Mention in a comment the voltage that the regulator expects. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/edp/edp_ctrl.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 4f7457b14dcce..149bfe7ddd82d 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -21,8 +21,6 @@ #include "edp.h" #include "edp.xml.h" -#define VDDA_MIN_UV 1800000 /* uV units */ -#define VDDA_MAX_UV 1800000 /* uV units */ #define VDDA_UA_ON_LOAD 100000 /* uA units */ #define VDDA_UA_OFF_LOAD 100 /* uA units */ @@ -67,7 +65,7 @@ struct edp_ctrl { void __iomem *base; /* regulators */ - struct regulator *vdda_vreg; + struct regulator *vdda_vreg; /* 1.8 V */ struct regulator *lvl_vreg; /* clocks */ @@ -329,12 +327,6 @@ static int edp_regulator_enable(struct edp_ctrl *ctrl) { int ret; - ret = regulator_set_voltage(ctrl->vdda_vreg, VDDA_MIN_UV, VDDA_MAX_UV); - if (ret) { - pr_err("%s:vdda_vreg set_voltage failed, %d\n", __func__, ret); - goto vdda_set_fail; - } - ret = regulator_set_load(ctrl->vdda_vreg, VDDA_UA_ON_LOAD); if (ret < 0) { pr_err("%s: vdda_vreg set regulator mode failed.\n", __func__); From ed19075be1100f8958066ed798e225173583eb2e Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 29 Apr 2016 15:19:37 +0530 Subject: [PATCH 18/25] drm/msm/mdp4: Don't manage DSI PLL regulators in MDP driver The MDP4 driver tries to request and set voltages for regulators required by the DSI PLLs. Firstly, the MDP4 driver shouldn't manage the DSI regulators, this should be handled in the DSI driver. Secondly, it shouldn't try to set a fixed voltage for regulators. Voltage constraints should be specified on the regulator via DT and managed by the regulator core. Remove all the DSI PLL regulator related code from the MDP4 driver. It's managed in the DSI driver for MSM8960/APQ8064 already. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 34 ------------------------- drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h | 2 -- 2 files changed, 36 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 76e1dfb5d25ea..67442d50a6c21 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -50,30 +50,6 @@ static int mdp4_hw_init(struct msm_kms *kms) mdp4_kms->rev = minor; - if (mdp4_kms->dsi_pll_vdda) { - if ((mdp4_kms->rev == 2) || (mdp4_kms->rev == 4)) { - ret = regulator_set_voltage(mdp4_kms->dsi_pll_vdda, - 1200000, 1200000); - if (ret) { - dev_err(dev->dev, - "failed to set dsi_pll_vdda voltage: %d\n", ret); - goto out; - } - } - } - - if (mdp4_kms->dsi_pll_vddio) { - if (mdp4_kms->rev == 2) { - ret = regulator_set_voltage(mdp4_kms->dsi_pll_vddio, - 1800000, 1800000); - if (ret) { - dev_err(dev->dev, - "failed to set dsi_pll_vddio voltage: %d\n", ret); - goto out; - } - } - } - if (mdp4_kms->rev > 1) { mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER0, 0x0707ffff); mdp4_write(mdp4_kms, REG_MDP4_CS_CONTROLLER1, 0x03073f3f); @@ -485,16 +461,6 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) goto fail; } - mdp4_kms->dsi_pll_vdda = - devm_regulator_get_optional(&pdev->dev, "dsi_pll_vdda"); - if (IS_ERR(mdp4_kms->dsi_pll_vdda)) - mdp4_kms->dsi_pll_vdda = NULL; - - mdp4_kms->dsi_pll_vddio = - devm_regulator_get_optional(&pdev->dev, "dsi_pll_vddio"); - if (IS_ERR(mdp4_kms->dsi_pll_vddio)) - mdp4_kms->dsi_pll_vddio = NULL; - /* NOTE: driver for this regulator still missing upstream.. use * _get_exclusive() and ignore the error if it does not exist * (and hope that the bootloader left it on for us) diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index b2828717be2ad..c5d045d5680d7 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -37,8 +37,6 @@ struct mdp4_kms { void __iomem *mmio; - struct regulator *dsi_pll_vdda; - struct regulator *dsi_pll_vddio; struct regulator *vdd; struct clk *clk; From 1193c3bcb581807d58dd7df90528ec744af387a9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 3 May 2016 09:46:49 -0400 Subject: [PATCH 19/25] drm/msm: drop return from gpu->submit() At this point, there is nothing left to fail. And submit already has a fence assigned and is added to the submit_list. Any problems from here on out are asynchronous (ie. hangcheck/recovery). Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/adreno/adreno_gpu.c | 4 +--- drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 +- drivers/gpu/drm/msm/msm_gpu.c | 4 ++-- drivers/gpu/drm/msm/msm_gpu.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 1d5a714d24a6b..fbe304ee6c809 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -133,7 +133,7 @@ void adreno_recover(struct msm_gpu *gpu) } } -int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, +void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -212,8 +212,6 @@ int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, #endif gpu->funcs->flush(gpu); - - return 0; } void adreno_flush(struct msm_gpu *gpu) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 1d07511f4d225..a54f6e036b4ab 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -238,7 +238,7 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); int adreno_hw_init(struct msm_gpu *gpu); uint32_t adreno_last_fence(struct msm_gpu *gpu); void adreno_recover(struct msm_gpu *gpu); -int adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, +void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx); void adreno_flush(struct msm_gpu *gpu); void adreno_idle(struct msm_gpu *gpu); diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index f94d01099e198..4c4f4b5abe2c5 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -540,12 +540,12 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); } - ret = gpu->funcs->submit(gpu, submit, ctx); + gpu->funcs->submit(gpu, submit, ctx); priv->lastctx = ctx; hangcheck_timer_reset(gpu); - return ret; + return 0; } /* diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 025e25b648e7f..c9022837a1a47 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -47,7 +47,7 @@ struct msm_gpu_funcs { int (*hw_init)(struct msm_gpu *gpu); int (*pm_suspend)(struct msm_gpu *gpu); int (*pm_resume)(struct msm_gpu *gpu); - int (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit, + void (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx); void (*flush)(struct msm_gpu *gpu); void (*idle)(struct msm_gpu *gpu); From 6860b56c4b84bf9dba479c3f881d45a0b09a879c Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 3 May 2016 09:49:40 -0400 Subject: [PATCH 20/25] drm/msm: de-indent submit_create() Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem_submit.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 2661a7cb23c8d..96c595c9ab936 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -40,17 +40,18 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, int sz = sizeof(*submit) + (nr * sizeof(submit->bos[0])); submit = kmalloc(sz, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY); - if (submit) { - submit->dev = dev; - submit->gpu = gpu; + if (!submit) + return NULL; - /* initially, until copy_from_user() and bo lookup succeeds: */ - submit->nr_bos = 0; - submit->nr_cmds = 0; + submit->dev = dev; + submit->gpu = gpu; - INIT_LIST_HEAD(&submit->bo_list); - ww_acquire_init(&submit->ticket, &reservation_ww_class); - } + /* initially, until copy_from_user() and bo lookup succeeds: */ + submit->nr_bos = 0; + submit->nr_cmds = 0; + + INIT_LIST_HEAD(&submit->bo_list); + ww_acquire_init(&submit->ticket, &reservation_ww_class); return submit; } From 40e6815bba6e34e5560e8855b43cd3eb17b24b09 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 3 May 2016 09:50:26 -0400 Subject: [PATCH 21/25] drm/msm: fix leak in failed submit path Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_drv.h | 1 + drivers/gpu/drm/msm/msm_gem_submit.c | 13 +++++++++++-- drivers/gpu/drm/msm/msm_gpu.c | 4 +--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 4114a40e4a09a..5b2963f32291b 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -161,6 +161,7 @@ int msm_atomic_commit(struct drm_device *dev, int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); +void msm_gem_submit_free(struct msm_gem_submit *submit); int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 96c595c9ab936..711a658cf1ea8 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -56,6 +56,13 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, return submit; } +void msm_gem_submit_free(struct msm_gem_submit *submit) +{ + fence_put(submit->fence); + list_del(&submit->node); + kfree(submit); +} + static int submit_lookup_objects(struct msm_gem_submit *submit, struct drm_msm_gem_submit *args, struct drm_file *file) { @@ -324,7 +331,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob return 0; } -static void submit_cleanup(struct msm_gem_submit *submit, bool fail) +static void submit_cleanup(struct msm_gem_submit *submit) { unsigned i; @@ -448,7 +455,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, args->fence = submit->fence->seqno; out: - submit_cleanup(submit, !!ret); + submit_cleanup(submit); + if (ret) + msm_gem_submit_free(submit); mutex_unlock(&dev->struct_mutex); return ret; } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 4c4f4b5abe2c5..5aed93a87e4c1 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -446,9 +446,7 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit) drm_gem_object_unreference(&msm_obj->base); } - fence_put(submit->fence); - list_del(&submit->node); - kfree(submit); + msm_gem_submit_free(submit); } static void retire_submits(struct msm_gpu *gpu) From 4816b6267cf078f40158ff2e6bf9d0223f0c1cf6 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 3 May 2016 10:10:15 -0400 Subject: [PATCH 22/25] drm/msm: print offender task name on hangcheck recovery Track the pid per submit, so we can print the name of the task which submitted the batch that caused the gpu to hang. Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_gem.h | 1 + drivers/gpu/drm/msm/msm_gem_submit.c | 2 ++ drivers/gpu/drm/msm/msm_gpu.c | 23 +++++++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 2771d155587af..9facd4b6ffd93 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -86,6 +86,7 @@ struct msm_gem_submit { struct list_head bo_list; struct ww_acquire_ctx ticket; struct fence *fence; + struct pid *pid; /* submitting process */ bool valid; /* true if no cmdstream patching needed */ unsigned int nr_cmds; unsigned int nr_bos; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 711a658cf1ea8..a9a001150b9ed 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -45,6 +45,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, submit->dev = dev; submit->gpu = gpu; + submit->pid = get_pid(task_pid(current)); /* initially, until copy_from_user() and bo lookup succeeds: */ submit->nr_bos = 0; @@ -60,6 +61,7 @@ void msm_gem_submit_free(struct msm_gem_submit *submit) { fence_put(submit->fence); list_del(&submit->node); + put_pid(submit->pid); kfree(submit); } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 5aed93a87e4c1..36ed53e661fe8 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -272,16 +272,30 @@ static void recover_worker(struct work_struct *work) { struct msm_gpu *gpu = container_of(work, struct msm_gpu, recover_work); struct drm_device *dev = gpu->dev; + struct msm_gem_submit *submit; uint32_t fence = gpu->funcs->last_fence(gpu); - dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); - msm_update_fence(gpu->fctx, fence + 1); mutex_lock(&dev->struct_mutex); - if (msm_gpu_active(gpu)) { - struct msm_gem_submit *submit; + dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); + list_for_each_entry(submit, &gpu->submit_list, node) { + if (submit->fence->seqno == (fence + 1)) { + struct task_struct *task; + + rcu_read_lock(); + task = pid_task(submit->pid, PIDTYPE_PID); + if (task) { + dev_err(dev->dev, "%s: offending task: %s\n", + gpu->name, task->comm); + } + rcu_read_unlock(); + break; + } + } + + if (msm_gpu_active(gpu)) { /* retire completed submits, plus the one that hung: */ retire_submits(gpu); @@ -293,6 +307,7 @@ static void recover_worker(struct work_struct *work) gpu->funcs->submit(gpu, submit, NULL); } } + mutex_unlock(&dev->struct_mutex); msm_gpu_retire(gpu); From c899f9358485869a6e18902233eb77b31f0428ee Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 2 May 2016 11:05:52 +0530 Subject: [PATCH 23/25] drm/msm/hdmi: Prevent gpio_free related kernel warnings Calling the legacy gpio_free on an invalid GPIO (a GPIO numbered -1) results in kernel warnings. This causes a lot of backtraces when we try to unload the drm/msm module. Call gpio_free only on valid GPIOs. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index 26129bff2dd69..e350b2e1fce16 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -112,6 +112,9 @@ static int gpio_config(struct hdmi *hdmi, bool on) for (i = 0; i < HDMI_MAX_NUM_GPIO; i++) { struct hdmi_gpio_data gpio = config->gpios[i]; + if (gpio.num == -1) + continue; + if (gpio.output) { int value = gpio.value ? 0 : 1; @@ -126,8 +129,10 @@ static int gpio_config(struct hdmi *hdmi, bool on) return 0; err: - while (i--) - gpio_free(config->gpios[i].num); + while (i--) { + if (config->gpios[i].num != -1) + gpio_free(config->gpios[i].num); + } return ret; } From 8208ed931eea9b00a3b29c9ef36da382b5480881 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 2 May 2016 11:05:53 +0530 Subject: [PATCH 24/25] drm/msm: Centralize connector registration/unregistration Move the drm_connector registration from the encoder(HDMI/DSI etc) drivers to the msm platform driver. This will simplify the task of ensuring that the connectors are registered only after the drm_device itself is registered. The connectors' destroy ops are made to use kzalloc instead of devm_kzalloc to ensure that that the connectors can be successfully unregistered when the msm driver module is removed. The memory for the connectors is unallocated when drm_mode_config_cleanup() is called during either during an error or during driver remove. Signed-off-by: Archit Taneja Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/dsi/dsi_manager.c | 27 +++++++------------ drivers/gpu/drm/msm/edp/edp_connector.c | 20 +++----------- drivers/gpu/drm/msm/hdmi/hdmi_connector.c | 17 +++--------- .../drm/msm/mdp/mdp4/mdp4_lvds_connector.c | 16 ++--------- drivers/gpu/drm/msm/msm_drv.c | 8 ++++++ 5 files changed, 26 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c index 58ba7ec17f512..c8d1f19c9a6d9 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c @@ -198,9 +198,13 @@ static enum drm_connector_status dsi_mgr_connector_detect( static void dsi_mgr_connector_destroy(struct drm_connector *connector) { + struct dsi_connector *dsi_connector = to_dsi_connector(connector); + DBG(""); - drm_connector_unregister(connector); + drm_connector_cleanup(connector); + + kfree(dsi_connector); } static void dsi_dual_connector_fix_modes(struct drm_connector *connector) @@ -538,12 +542,9 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) struct dsi_connector *dsi_connector; int ret, i; - dsi_connector = devm_kzalloc(msm_dsi->dev->dev, - sizeof(*dsi_connector), GFP_KERNEL); - if (!dsi_connector) { - ret = -ENOMEM; - goto fail; - } + dsi_connector = kzalloc(sizeof(*dsi_connector), GFP_KERNEL); + if (!dsi_connector) + return ERR_PTR(-ENOMEM); dsi_connector->id = id; @@ -552,7 +553,7 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) ret = drm_connector_init(msm_dsi->dev, connector, &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI); if (ret) - goto fail; + return ERR_PTR(ret); drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs); @@ -565,21 +566,11 @@ struct drm_connector *msm_dsi_manager_connector_init(u8 id) connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - ret = drm_connector_register(connector); - if (ret) - goto fail; - for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) drm_mode_connector_attach_encoder(connector, msm_dsi->encoders[i]); return connector; - -fail: - if (connector) - dsi_mgr_connector_destroy(connector); - - return ERR_PTR(ret); } /* initialize bridge */ diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c index b4d1b469862a4..72360cd038c02 100644 --- a/drivers/gpu/drm/msm/edp/edp_connector.c +++ b/drivers/gpu/drm/msm/edp/edp_connector.c @@ -37,7 +37,7 @@ static void edp_connector_destroy(struct drm_connector *connector) struct edp_connector *edp_connector = to_edp_connector(connector); DBG(""); - drm_connector_unregister(connector); + drm_connector_cleanup(connector); kfree(edp_connector); @@ -124,10 +124,8 @@ struct drm_connector *msm_edp_connector_init(struct msm_edp *edp) int ret; edp_connector = kzalloc(sizeof(*edp_connector), GFP_KERNEL); - if (!edp_connector) { - ret = -ENOMEM; - goto fail; - } + if (!edp_connector) + return ERR_PTR(-ENOMEM); edp_connector->edp = edp; @@ -136,7 +134,7 @@ struct drm_connector *msm_edp_connector_init(struct msm_edp *edp) ret = drm_connector_init(edp->dev, connector, &edp_connector_funcs, DRM_MODE_CONNECTOR_eDP); if (ret) - goto fail; + return ERR_PTR(ret); drm_connector_helper_add(connector, &edp_connector_helper_funcs); @@ -147,17 +145,7 @@ struct drm_connector *msm_edp_connector_init(struct msm_edp *edp) connector->interlace_allowed = false; connector->doublescan_allowed = false; - ret = drm_connector_register(connector); - if (ret) - goto fail; - drm_mode_connector_attach_encoder(connector, edp->encoder); return connector; - -fail: - if (connector) - edp_connector_destroy(connector); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index e350b2e1fce16..b15d72683112d 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -346,7 +346,6 @@ static void hdmi_connector_destroy(struct drm_connector *connector) hdp_disable(hdmi_connector); - drm_connector_unregister(connector); drm_connector_cleanup(connector); kfree(hdmi_connector); @@ -438,10 +437,8 @@ struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi) int ret; hdmi_connector = kzalloc(sizeof(*hdmi_connector), GFP_KERNEL); - if (!hdmi_connector) { - ret = -ENOMEM; - goto fail; - } + if (!hdmi_connector) + return ERR_PTR(-ENOMEM); hdmi_connector->hdmi = hdmi; INIT_WORK(&hdmi_connector->hpd_work, msm_hdmi_hotplug_work); @@ -458,21 +455,13 @@ struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi) connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_connector_register(connector); - ret = hpd_enable(hdmi_connector); if (ret) { dev_err(&hdmi->pdev->dev, "failed to enable HPD: %d\n", ret); - goto fail; + return ERR_PTR(ret); } drm_mode_connector_attach_encoder(connector, hdmi->encoder); return connector; - -fail: - if (connector) - hdmi_connector_destroy(connector); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c index e73e1742b2500..2648cd7631efc 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c @@ -48,7 +48,6 @@ static void mdp4_lvds_connector_destroy(struct drm_connector *connector) struct mdp4_lvds_connector *mdp4_lvds_connector = to_mdp4_lvds_connector(connector); - drm_connector_unregister(connector); drm_connector_cleanup(connector); kfree(mdp4_lvds_connector); @@ -121,13 +120,10 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, { struct drm_connector *connector = NULL; struct mdp4_lvds_connector *mdp4_lvds_connector; - int ret; mdp4_lvds_connector = kzalloc(sizeof(*mdp4_lvds_connector), GFP_KERNEL); - if (!mdp4_lvds_connector) { - ret = -ENOMEM; - goto fail; - } + if (!mdp4_lvds_connector) + return ERR_PTR(-ENOMEM); mdp4_lvds_connector->encoder = encoder; mdp4_lvds_connector->panel_node = panel_node; @@ -143,15 +139,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, connector->interlace_allowed = 0; connector->doublescan_allowed = 0; - drm_connector_register(connector); - drm_mode_connector_attach_encoder(connector, encoder); return connector; - -fail: - if (connector) - mdp4_lvds_connector_destroy(connector); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index c257cdd346e75..336070d5eadcf 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -199,6 +199,8 @@ static int msm_unload(struct drm_device *dev) drm_kms_helper_poll_fini(dev); + drm_connector_unregister_all(dev); + #ifdef CONFIG_DRM_FBDEV_EMULATION if (fbdev && priv->fbdev) msm_fbdev_free(dev); @@ -414,6 +416,12 @@ static int msm_load(struct drm_device *dev, unsigned long flags) goto fail; } + ret = drm_connector_register_all(dev); + if (ret) { + dev_err(dev->dev, "failed to register connectors\n"); + goto fail; + } + drm_mode_config_reset(dev); #ifdef CONFIG_DRM_FBDEV_EMULATION From 2b669875332fbdff0a7ad559e8662e875e7a1526 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 2 May 2016 11:05:54 +0530 Subject: [PATCH 25/25] drm/msm: Drop load/unload drm_driver ops The load/unload drm_driver ops are deprecated. They should be removed as they result in creation of devices visible to userspace even before the drm_device is registered. Drop these ops and use drm_dev_alloc/register and drm_dev_unregister/unref to explicitly create and destroy the drm device in the msm platform driver's bind and unbind ops. With this in use, the drm connectors are only registered once the drm_device is registered. It also fixes the issue of stray debugfs files after the msm module is removed. With this, all the debugfs files are removed, and allows successive module insertions/removals. Signed-off-by: Archit Taneja --- drivers/gpu/drm/msm/msm_drv.c | 125 +++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 336070d5eadcf..9788989ea21c6 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -175,13 +175,11 @@ static int vblank_ctrl_queue_work(struct msm_drm_private *priv, return 0; } -/* - * DRM operations: - */ - -static int msm_unload(struct drm_device *dev) +static int msm_drm_uninit(struct device *dev) { - struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = ddev->dev_private; struct msm_kms *kms = priv->kms; struct msm_gpu *gpu = priv->gpu; struct msm_vblank_ctrl *vbl_ctrl = &priv->vblank_ctrl; @@ -197,20 +195,21 @@ static int msm_unload(struct drm_device *dev) kfree(vbl_ev); } - drm_kms_helper_poll_fini(dev); + drm_kms_helper_poll_fini(ddev); + + drm_connector_unregister_all(ddev); - drm_connector_unregister_all(dev); + drm_dev_unregister(ddev); #ifdef CONFIG_DRM_FBDEV_EMULATION if (fbdev && priv->fbdev) - msm_fbdev_free(dev); + msm_fbdev_free(ddev); #endif - drm_mode_config_cleanup(dev); - drm_vblank_cleanup(dev); + drm_mode_config_cleanup(ddev); - pm_runtime_get_sync(dev->dev); - drm_irq_uninstall(dev); - pm_runtime_put_sync(dev->dev); + pm_runtime_get_sync(dev); + drm_irq_uninstall(ddev); + pm_runtime_put_sync(dev); flush_workqueue(priv->wq); destroy_workqueue(priv->wq); @@ -219,14 +218,14 @@ static int msm_unload(struct drm_device *dev) destroy_workqueue(priv->atomic_wq); if (kms) { - pm_runtime_disable(dev->dev); + pm_runtime_disable(dev); kms->funcs->destroy(kms); } if (gpu) { - mutex_lock(&dev->struct_mutex); + mutex_lock(&ddev->struct_mutex); gpu->funcs->pm_suspend(gpu); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&ddev->struct_mutex); gpu->funcs->destroy(gpu); } @@ -234,13 +233,14 @@ static int msm_unload(struct drm_device *dev) DEFINE_DMA_ATTRS(attrs); dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); drm_mm_takedown(&priv->vram.mm); - dma_free_attrs(dev->dev, priv->vram.size, NULL, - priv->vram.paddr, &attrs); + dma_free_attrs(dev, priv->vram.size, NULL, + priv->vram.paddr, &attrs); } - component_unbind_all(dev->dev, dev); + component_unbind_all(dev, ddev); - dev->dev_private = NULL; + ddev->dev_private = NULL; + drm_dev_unref(ddev); kfree(priv); @@ -328,20 +328,30 @@ static int msm_init_vram(struct drm_device *dev) return ret; } -static int msm_load(struct drm_device *dev, unsigned long flags) +static int msm_drm_init(struct device *dev, struct drm_driver *drv) { - struct platform_device *pdev = dev->platformdev; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev; struct msm_drm_private *priv; struct msm_kms *kms; int ret; + ddev = drm_dev_alloc(drv, dev); + if (!ddev) { + dev_err(dev, "failed to allocate drm_device\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, ddev); + ddev->platformdev = pdev; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { - dev_err(dev->dev, "failed to allocate private data\n"); + drm_dev_unref(ddev); return -ENOMEM; } - dev->dev_private = priv; + ddev->dev_private = priv; priv->wq = alloc_ordered_workqueue("msm", 0); priv->atomic_wq = alloc_ordered_workqueue("msm:atomic", 0); @@ -352,25 +362,26 @@ static int msm_load(struct drm_device *dev, unsigned long flags) INIT_WORK(&priv->vblank_ctrl.work, vblank_ctrl_worker); spin_lock_init(&priv->vblank_ctrl.lock); - drm_mode_config_init(dev); - - platform_set_drvdata(pdev, dev); + drm_mode_config_init(ddev); /* Bind all our sub-components: */ - ret = component_bind_all(dev->dev, dev); - if (ret) + ret = component_bind_all(dev, ddev); + if (ret) { + kfree(priv); + drm_dev_unref(ddev); return ret; + } - ret = msm_init_vram(dev); + ret = msm_init_vram(ddev); if (ret) goto fail; switch (get_mdp_ver(pdev)) { case 4: - kms = mdp4_kms_init(dev); + kms = mdp4_kms_init(ddev); break; case 5: - kms = mdp5_kms_init(dev); + kms = mdp5_kms_init(ddev); break; default: kms = ERR_PTR(-ENODEV); @@ -384,7 +395,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) * and (for example) use dmabuf/prime to share buffers with * imx drm driver on iMX5 */ - dev_err(dev->dev, "failed to load kms\n"); + dev_err(dev, "failed to load kms\n"); ret = PTR_ERR(kms); goto fail; } @@ -392,56 +403,64 @@ static int msm_load(struct drm_device *dev, unsigned long flags) priv->kms = kms; if (kms) { - pm_runtime_enable(dev->dev); + pm_runtime_enable(dev); ret = kms->funcs->hw_init(kms); if (ret) { - dev_err(dev->dev, "kms hw init failed: %d\n", ret); + dev_err(dev, "kms hw init failed: %d\n", ret); goto fail; } } - dev->mode_config.funcs = &mode_config_funcs; + ddev->mode_config.funcs = &mode_config_funcs; - ret = drm_vblank_init(dev, priv->num_crtcs); + ret = drm_vblank_init(ddev, priv->num_crtcs); if (ret < 0) { - dev_err(dev->dev, "failed to initialize vblank\n"); + dev_err(dev, "failed to initialize vblank\n"); goto fail; } - pm_runtime_get_sync(dev->dev); - ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); - pm_runtime_put_sync(dev->dev); + pm_runtime_get_sync(dev); + ret = drm_irq_install(ddev, platform_get_irq(pdev, 0)); + pm_runtime_put_sync(dev); if (ret < 0) { - dev_err(dev->dev, "failed to install IRQ handler\n"); + dev_err(dev, "failed to install IRQ handler\n"); goto fail; } - ret = drm_connector_register_all(dev); + ret = drm_dev_register(ddev, 0); + if (ret) + goto fail; + + ret = drm_connector_register_all(ddev); if (ret) { - dev_err(dev->dev, "failed to register connectors\n"); + dev_err(dev, "failed to register connectors\n"); goto fail; } - drm_mode_config_reset(dev); + drm_mode_config_reset(ddev); #ifdef CONFIG_DRM_FBDEV_EMULATION if (fbdev) - priv->fbdev = msm_fbdev_init(dev); + priv->fbdev = msm_fbdev_init(ddev); #endif - ret = msm_debugfs_late_init(dev); + ret = msm_debugfs_late_init(ddev); if (ret) goto fail; - drm_kms_helper_poll_init(dev); + drm_kms_helper_poll_init(ddev); return 0; fail: - msm_unload(dev); + msm_drm_uninit(dev); return ret; } +/* + * DRM operations: + */ + static void load_gpu(struct drm_device *dev) { static DEFINE_MUTEX(init_lock); @@ -708,8 +727,6 @@ static struct drm_driver msm_driver = { DRIVER_RENDER | DRIVER_ATOMIC | DRIVER_MODESET, - .load = msm_load, - .unload = msm_unload, .open = msm_open, .preclose = msm_preclose, .lastclose = msm_lastclose, @@ -809,12 +826,12 @@ static int add_components(struct device *dev, struct component_match **matchptr, static int msm_drm_bind(struct device *dev) { - return drm_platform_init(&msm_driver, to_platform_device(dev)); + return msm_drm_init(dev, &msm_driver); } static void msm_drm_unbind(struct device *dev) { - drm_put_dev(platform_get_drvdata(to_platform_device(dev))); + msm_drm_uninit(dev); } static const struct component_master_ops msm_drm_ops = {