Merge remote-tracking branch 'msm/msm-fixes' into HEAD
authorDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Wed, 2 Nov 2022 14:37:08 +0000 (17:37 +0300)
committerDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Wed, 2 Nov 2022 14:37:08 +0000 (17:37 +0300)
17 files changed:
drivers/gpu/drm/msm/Kconfig
drivers/gpu/drm/msm/adreno/a6xx_gpu_state.c
drivers/gpu/drm/msm/adreno/adreno_device.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_connector.c
drivers/gpu/drm/msm/dp/dp_ctrl.c
drivers/gpu/drm/msm/dp/dp_display.c
drivers/gpu/drm/msm/dp/dp_drm.c
drivers/gpu/drm/msm/dp/dp_parser.c
drivers/gpu/drm/msm/dp/dp_parser.h
drivers/gpu/drm/msm/dsi/dsi.c
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_ringbuffer.c

index 4e0cbd6..3c9dfdb 100644 (file)
@@ -155,7 +155,7 @@ config DRM_MSM_HDMI
          Compile in support for the HDMI output MSM DRM driver. It can
          be a primary or a secondary display on device. Note that this is used
          only for the direct HDMI output. If the device outputs HDMI data
-         throught some kind of DSI-to-HDMI bridge, this option can be disabled.
+         through some kind of DSI-to-HDMI bridge, this option can be disabled.
 
 config DRM_MSM_HDMI_HDCP
        bool "Enable HDMI HDCP support in MSM DRM driver"
index 55f4433..a5c3d1e 100644 (file)
@@ -91,7 +91,7 @@ struct a6xx_state_memobj {
 static void *state_kcalloc(struct a6xx_gpu_state *a6xx_state, int nr, size_t objsize)
 {
        struct a6xx_state_memobj *obj =
-               kzalloc((nr * objsize) + sizeof(*obj), GFP_KERNEL);
+               kvzalloc((nr * objsize) + sizeof(*obj), GFP_KERNEL);
 
        if (!obj)
                return NULL;
@@ -813,6 +813,9 @@ static struct msm_gpu_state_bo *a6xx_snapshot_gmu_bo(
 {
        struct msm_gpu_state_bo *snapshot;
 
+       if (!bo->size)
+               return NULL;
+
        snapshot = state_kcalloc(a6xx_state, 1, sizeof(*snapshot));
        if (!snapshot)
                return NULL;
@@ -1040,8 +1043,13 @@ static void a6xx_gpu_state_destroy(struct kref *kref)
        if (a6xx_state->gmu_hfi)
                kvfree(a6xx_state->gmu_hfi->data);
 
-       list_for_each_entry_safe(obj, tmp, &a6xx_state->objs, node)
-               kfree(obj);
+       if (a6xx_state->gmu_debug)
+               kvfree(a6xx_state->gmu_debug->data);
+
+       list_for_each_entry_safe(obj, tmp, &a6xx_state->objs, node) {
+               list_del(&obj->node);
+               kvfree(obj);
+       }
 
        adreno_gpu_state_destroy(state);
        kfree(a6xx_state);
index 24b489b..6288064 100644 (file)
@@ -679,6 +679,9 @@ static int adreno_system_suspend(struct device *dev)
        struct msm_gpu *gpu = dev_to_gpu(dev);
        int remaining, ret;
 
+       if (!gpu)
+               return 0;
+
        suspend_scheduler(gpu);
 
        remaining = wait_event_timeout(gpu->retire_event,
@@ -700,7 +703,12 @@ out:
 
 static int adreno_system_resume(struct device *dev)
 {
-       resume_scheduler(dev_to_gpu(dev));
+       struct msm_gpu *gpu = dev_to_gpu(dev);
+
+       if (!gpu)
+               return 0;
+
+       resume_scheduler(gpu);
        return pm_runtime_force_resume(dev);
 }
 
index 382fb7f..5a0e849 100644 (file)
@@ -729,7 +729,12 @@ static char *adreno_gpu_ascii85_encode(u32 *src, size_t len)
        return buf;
 }
 
-/* len is expected to be in bytes */
+/* len is expected to be in bytes
+ *
+ * WARNING: *ptr should be allocated with kvmalloc or friends.  It can be free'd
+ * with kvfree() and replaced with a newly kvmalloc'd buffer on the first call
+ * when the unencoded raw data is encoded
+ */
 void adreno_show_object(struct drm_printer *p, void **ptr, int len,
                bool *encoded)
 {
index 7288041..7444b75 100644 (file)
@@ -56,8 +56,9 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
        return ret;
 }
 
-static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
-                                struct drm_display_mode *mode)
+static enum drm_mode_status
+mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
+                              struct drm_display_mode *mode)
 {
        struct mdp4_lvds_connector *mdp4_lvds_connector =
                        to_mdp4_lvds_connector(connector);
index 3854c9f..dd26ca6 100644 (file)
@@ -1243,8 +1243,7 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
 {
        int ret = 0;
        const u8 *dpcd = ctrl->panel->dpcd;
-       u8 encoding = DP_SET_ANSI_8B10B;
-       u8 ssc;
+       u8 encoding[] = { 0, DP_SET_ANSI_8B10B };
        u8 assr;
        struct dp_link_info link_info = {0};
 
@@ -1256,13 +1255,11 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
 
        dp_aux_link_configure(ctrl->aux, &link_info);
 
-       if (drm_dp_max_downspread(dpcd)) {
-               ssc = DP_SPREAD_AMP_0_5;
-               drm_dp_dpcd_write(ctrl->aux, DP_DOWNSPREAD_CTRL, &ssc, 1);
-       }
+       if (drm_dp_max_downspread(dpcd))
+               encoding[0] |= DP_SPREAD_AMP_0_5;
 
-       drm_dp_dpcd_write(ctrl->aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
-                               &encoding, 1);
+       /* config DOWNSPREAD_CTRL and MAIN_LINK_CHANNEL_CODING_SET */
+       drm_dp_dpcd_write(ctrl->aux, DP_DOWNSPREAD_CTRL, encoding, 2);
 
        if (drm_dp_alternate_scrambler_reset_cap(dpcd)) {
                assr = DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
index bfd0aef..a49f6db 100644 (file)
@@ -1249,7 +1249,7 @@ int dp_display_request_irq(struct msm_dp *dp_display)
                return -EINVAL;
        }
 
-       rc = devm_request_irq(&dp->pdev->dev, dp->irq,
+       rc = devm_request_irq(dp_display->drm_dev->dev, dp->irq,
                        dp_display_irq_handler,
                        IRQF_TRIGGER_HIGH, "dp_display_isr", dp);
        if (rc < 0) {
@@ -1528,6 +1528,11 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor)
        }
 }
 
+static void of_dp_aux_depopulate_bus_void(void *data)
+{
+       of_dp_aux_depopulate_bus(data);
+}
+
 static int dp_display_get_next_bridge(struct msm_dp *dp)
 {
        int rc;
@@ -1552,10 +1557,16 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
                 * panel driver is probed asynchronously but is the best we
                 * can do without a bigger driver reorganization.
                 */
-               rc = devm_of_dp_aux_populate_ep_devices(dp_priv->aux);
+               rc = of_dp_aux_populate_bus(dp_priv->aux, NULL);
                of_node_put(aux_bus);
                if (rc)
                        goto error;
+
+               rc = devm_add_action_or_reset(dp->drm_dev->dev,
+                                               of_dp_aux_depopulate_bus_void,
+                                               dp_priv->aux);
+               if (rc)
+                       goto error;
        } else if (dp->is_edp) {
                DRM_ERROR("eDP aux_bus not found\n");
                return -ENODEV;
@@ -1568,7 +1579,7 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
         * For DisplayPort interfaces external bridges are optional, so
         * silently ignore an error if one is not present (-ENODEV).
         */
-       rc = dp_parser_find_next_bridge(dp_priv->parser);
+       rc = devm_dp_parser_find_next_bridge(dp->drm_dev->dev, dp_priv->parser);
        if (!dp->is_edp && rc == -ENODEV)
                return 0;
 
@@ -1597,6 +1608,12 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
                return -EINVAL;
 
        priv = dev->dev_private;
+
+       if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
+               DRM_DEV_ERROR(dev->dev, "too many bridges\n");
+               return -ENOSPC;
+       }
+
        dp_display->drm_dev = dev;
 
        dp_priv = container_of(dp_display, struct dp_display_private, dp_display);
index 6df25f7..6db82f9 100644 (file)
@@ -31,6 +31,36 @@ static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge)
                                        connector_status_disconnected;
 }
 
+static int dp_bridge_atomic_check(struct drm_bridge *bridge,
+                           struct drm_bridge_state *bridge_state,
+                           struct drm_crtc_state *crtc_state,
+                           struct drm_connector_state *conn_state)
+{
+       struct msm_dp *dp;
+
+       dp = to_dp_bridge(bridge)->dp_display;
+
+       drm_dbg_dp(dp->drm_dev, "is_connected = %s\n",
+               (dp->is_connected) ? "true" : "false");
+
+       /*
+        * There is no protection in the DRM framework to check if the display
+        * pipeline has been already disabled before trying to disable it again.
+        * Hence if the sink is unplugged, the pipeline gets disabled, but the
+        * crtc->active is still true. Any attempt to set the mode or manually
+        * disable this encoder will result in the crash.
+        *
+        * TODO: add support for telling the DRM subsystem that the pipeline is
+        * disabled by the hardware and thus all access to it should be forbidden.
+        * After that this piece of code can be removed.
+        */
+       if (bridge->ops & DRM_BRIDGE_OP_HPD)
+               return (dp->is_connected) ? 0 : -ENOTCONN;
+
+       return 0;
+}
+
+
 /**
  * dp_bridge_get_modes - callback to add drm modes via drm_mode_probed_add()
  * @bridge: Poiner to drm bridge
@@ -61,6 +91,9 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *
 }
 
 static const struct drm_bridge_funcs dp_bridge_ops = {
+       .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+       .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
+       .atomic_reset           = drm_atomic_helper_bridge_reset,
        .enable       = dp_bridge_enable,
        .disable      = dp_bridge_disable,
        .post_disable = dp_bridge_post_disable,
@@ -68,6 +101,7 @@ static const struct drm_bridge_funcs dp_bridge_ops = {
        .mode_valid   = dp_bridge_mode_valid,
        .get_modes    = dp_bridge_get_modes,
        .detect       = dp_bridge_detect,
+       .atomic_check = dp_bridge_atomic_check,
 };
 
 struct drm_bridge *dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev,
index dd73221..dcbe893 100644 (file)
@@ -240,12 +240,12 @@ static int dp_parser_clock(struct dp_parser *parser)
        return 0;
 }
 
-int dp_parser_find_next_bridge(struct dp_parser *parser)
+int devm_dp_parser_find_next_bridge(struct device *dev, struct dp_parser *parser)
 {
-       struct device *dev = &parser->pdev->dev;
+       struct platform_device *pdev = parser->pdev;
        struct drm_bridge *bridge;
 
-       bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0);
+       bridge = devm_drm_of_get_bridge(dev, pdev->dev.of_node, 1, 0);
        if (IS_ERR(bridge))
                return PTR_ERR(bridge);
 
index 866c1a8..d30ab77 100644 (file)
@@ -138,8 +138,9 @@ struct dp_parser {
 struct dp_parser *dp_parser_get(struct platform_device *pdev);
 
 /**
- * dp_parser_find_next_bridge() - find an additional bridge to DP
+ * devm_dp_parser_find_next_bridge() - find an additional bridge to DP
  *
+ * @dev: device to tie bridge lifetime to
  * @parser: dp_parser data from client
  *
  * This function is used to find any additional bridge attached to
@@ -147,6 +148,6 @@ struct dp_parser *dp_parser_get(struct platform_device *pdev);
  *
  * Return: 0 if able to get the bridge, otherwise negative errno for failure.
  */
-int dp_parser_find_next_bridge(struct dp_parser *parser);
+int devm_dp_parser_find_next_bridge(struct device *dev, struct dp_parser *parser);
 
 #endif
index 39bbabb..8a95c74 100644 (file)
@@ -218,6 +218,12 @@ int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
                return -EINVAL;
 
        priv = dev->dev_private;
+
+       if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
+               DRM_DEV_ERROR(dev->dev, "too many bridges\n");
+               return -ENOSPC;
+       }
+
        msm_dsi->dev = dev;
 
        ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
index 93fe61b..f28fb21 100644 (file)
@@ -300,6 +300,11 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
        struct platform_device *pdev = hdmi->pdev;
        int ret;
 
+       if (priv->num_bridges == ARRAY_SIZE(priv->bridges)) {
+               DRM_DEV_ERROR(dev->dev, "too many bridges\n");
+               return -ENOSPC;
+       }
+
        hdmi->dev = dev;
        hdmi->encoder = encoder;
 
@@ -339,7 +344,7 @@ int msm_hdmi_modeset_init(struct hdmi *hdmi,
                goto fail;
        }
 
-       ret = devm_request_irq(&pdev->dev, hdmi->irq,
+       ret = devm_request_irq(dev->dev, hdmi->irq,
                        msm_hdmi_irq, IRQF_TRIGGER_HIGH,
                        "hdmi_isr", hdmi);
        if (ret < 0) {
index 28034c2..105b5b4 100644 (file)
@@ -247,6 +247,7 @@ static int msm_drm_uninit(struct device *dev)
 
        for (i = 0; i < priv->num_bridges; i++)
                drm_bridge_remove(priv->bridges[i]);
+       priv->num_bridges = 0;
 
        pm_runtime_get_sync(dev);
        msm_irq_uninstall(ddev);
index 5599d93..45a3e5c 100644 (file)
@@ -501,11 +501,11 @@ out:
  */
 static void submit_cleanup(struct msm_gem_submit *submit, bool error)
 {
-       unsigned cleanup_flags = BO_LOCKED | BO_OBJ_PINNED;
+       unsigned cleanup_flags = BO_LOCKED;
        unsigned i;
 
        if (error)
-               cleanup_flags |= BO_VMA_PINNED;
+               cleanup_flags |= BO_VMA_PINNED | BO_OBJ_PINNED;
 
        for (i = 0; i < submit->nr_bos; i++) {
                struct msm_gem_object *msm_obj = submit->bos[i].obj;
@@ -706,7 +706,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
        struct msm_drm_private *priv = dev->dev_private;
        struct drm_msm_gem_submit *args = data;
        struct msm_file_private *ctx = file->driver_priv;
-       struct msm_gem_submit *submit = NULL;
+       struct msm_gem_submit *submit;
        struct msm_gpu *gpu = priv->gpu;
        struct msm_gpu_submitqueue *queue;
        struct msm_ringbuffer *ring;
@@ -946,8 +946,7 @@ out_unlock:
                put_unused_fd(out_fence_fd);
        mutex_unlock(&queue->lock);
 out_post_unlock:
-       if (submit)
-               msm_gem_submit_put(submit);
+       msm_gem_submit_put(submit);
        if (!IS_ERR_OR_NULL(post_deps)) {
                for (i = 0; i < args->nr_out_syncobjs; ++i) {
                        kfree(post_deps[i].chain);
index 0098ee8..021f4e2 100644 (file)
@@ -997,4 +997,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)
        }
 
        msm_devfreq_cleanup(gpu);
+
+       platform_set_drvdata(gpu->pdev, NULL);
 }
index ff911e7..58a72e6 100644 (file)
@@ -280,6 +280,10 @@ struct msm_gpu {
 static inline struct msm_gpu *dev_to_gpu(struct device *dev)
 {
        struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(dev);
+
+       if (!adreno_smmu)
+               return NULL;
+
        return container_of(adreno_smmu, struct msm_gpu, adreno_smmu);
 }
 
index cad4c35..57a8e95 100644 (file)
@@ -25,7 +25,8 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job)
 
                msm_gem_lock(obj);
                msm_gem_unpin_vma_fenced(submit->bos[i].vma, fctx);
-               submit->bos[i].flags &= ~BO_VMA_PINNED;
+               msm_gem_unpin_locked(obj);
+               submit->bos[i].flags &= ~(BO_VMA_PINNED | BO_OBJ_PINNED);
                msm_gem_unlock(obj);
        }