On 04.12.2015 00:26, cpaul at redhat.com wrote:
> From: Lyude <cpaul at redhat.com>
>
> HPD signals on DVI ports can be fired off before the pins required for
> DDC probing actually make contact, due to the pins for HPD making
> contact first. This results in a HPD signal being asserted but DDC
> probing failing, resulting in hotplugging occasionally failing.
>
> This is somewhat rare on most cards (depending on what angle you plug
> the DVI connector in), but on some cards it happens constantly. The
> Radeon R5 on the machine used for testing this patch for instance, runs
> into this issue just about every time I try to hotplug a DVI monitor and
> as a result hotplugging almost never works.
>
> Rescheduling the hotplug work for a second when we run into an HPD
> signal with a failing DDC probe usually gives enough time for the rest
> of the connector's pins to make contact, and fixes this issue.
>
> Signed-off-by: Lyude <cpaul at redhat.com>

I find a second a bit long, but if it works so what?

Looks sane enough to me, patch is Reviewed-by: Christian König 
<christian.koenig at amd.com>

> ---
> Sending this version of the patch because Jerome says this will probably be 
> the
> least controversial of the potential fixes. Instead of sending userspace tons 
> of
> hotplug events, we just reschedule the hotplug work.
>
>   drivers/gpu/drm/radeon/cik.c               |  2 +-
>   drivers/gpu/drm/radeon/evergreen.c         |  2 +-
>   drivers/gpu/drm/radeon/r100.c              |  2 +-
>   drivers/gpu/drm/radeon/r600.c              |  2 +-
>   drivers/gpu/drm/radeon/radeon.h            |  2 +-
>   drivers/gpu/drm/radeon/radeon_connectors.c | 21 ++++++++++++++++++++-
>   drivers/gpu/drm/radeon/radeon_irq_kms.c    |  8 ++++----
>   drivers/gpu/drm/radeon/radeon_mode.h       |  1 +
>   drivers/gpu/drm/radeon/rs600.c             |  2 +-
>   drivers/gpu/drm/radeon/si.c                |  2 +-
>   10 files changed, 32 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index 248953d..6801a0c 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -8472,7 +8472,7 @@ restart_ih:
>       if (queue_dp)
>               schedule_work(&rdev->dp_work);
>       if (queue_hotplug)
> -             schedule_work(&rdev->hotplug_work);
> +             schedule_delayed_work(&rdev->hotplug_work, 0);
>       if (queue_reset) {
>               rdev->needs_reset = true;
>               wake_up_all(&rdev->fence_queue);
> diff --git a/drivers/gpu/drm/radeon/evergreen.c 
> b/drivers/gpu/drm/radeon/evergreen.c
> index 0acde19..f8e4986 100644
> --- a/drivers/gpu/drm/radeon/evergreen.c
> +++ b/drivers/gpu/drm/radeon/evergreen.c
> @@ -5368,7 +5368,7 @@ restart_ih:
>       if (queue_dp)
>               schedule_work(&rdev->dp_work);
>       if (queue_hotplug)
> -             schedule_work(&rdev->hotplug_work);
> +             schedule_delayed_work(&rdev->hotplug_work, 0);
>       if (queue_hdmi)
>               schedule_work(&rdev->audio_work);
>       if (queue_thermal && rdev->pm.dpm_enabled)
> diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
> index 238b13f..2df3c86 100644
> --- a/drivers/gpu/drm/radeon/r100.c
> +++ b/drivers/gpu/drm/radeon/r100.c
> @@ -806,7 +806,7 @@ int r100_irq_process(struct radeon_device *rdev)
>               status = r100_irq_ack(rdev);
>       }
>       if (queue_hotplug)
> -             schedule_work(&rdev->hotplug_work);
> +             schedule_delayed_work(&rdev->hotplug_work, 0);
>       if (rdev->msi_enabled) {
>               switch (rdev->family) {
>               case CHIP_RS400:
> diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
> index 4ea5b10..cc2fdf0 100644
> --- a/drivers/gpu/drm/radeon/r600.c
> +++ b/drivers/gpu/drm/radeon/r600.c
> @@ -4276,7 +4276,7 @@ restart_ih:
>               WREG32(IH_RB_RPTR, rptr);
>       }
>       if (queue_hotplug)
> -             schedule_work(&rdev->hotplug_work);
> +             schedule_delayed_work(&rdev->hotplug_work, 0);
>       if (queue_hdmi)
>               schedule_work(&rdev->audio_work);
>       if (queue_thermal && rdev->pm.dpm_enabled)
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index b6cbd81..87db649 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -2414,7 +2414,7 @@ struct radeon_device {
>       struct r600_ih ih; /* r6/700 interrupt ring */
>       struct radeon_rlc rlc;
>       struct radeon_mec mec;
> -     struct work_struct hotplug_work;
> +     struct delayed_work hotplug_work;
>       struct work_struct dp_work;
>       struct work_struct audio_work;
>       int num_crtc; /* number of crtcs */
> diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c 
> b/drivers/gpu/drm/radeon/radeon_connectors.c
> index 5a2cafb..340f3f5 100644
> --- a/drivers/gpu/drm/radeon/radeon_connectors.c
> +++ b/drivers/gpu/drm/radeon/radeon_connectors.c
> @@ -1234,13 +1234,32 @@ radeon_dvi_detect(struct drm_connector *connector, 
> bool force)
>       if (r < 0)
>               return connector_status_disconnected;
>   
> +     if (radeon_connector->detected_hpd_without_ddc) {
> +             force = true;
> +             radeon_connector->detected_hpd_without_ddc = false;
> +     }
> +
>       if (!force && radeon_check_hpd_status_unchanged(connector)) {
>               ret = connector->status;
>               goto exit;
>       }
>   
> -     if (radeon_connector->ddc_bus)
> +     if (radeon_connector->ddc_bus) {
>               dret = radeon_ddc_probe(radeon_connector, false);
> +
> +             /* Sometimes the pins required for the DDC probe on DVI
> +              * connectors don't make contact at the same time that the ones
> +              * for HPD do. If the DDC probe fails even though we had an HPD
> +              * signal, try again later */
> +             if (!dret && !force &&
> +                 connector->status != connector_status_connected) {
> +                     DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 
> second\n");
> +                     radeon_connector->detected_hpd_without_ddc = true;
> +                     schedule_delayed_work(&rdev->hotplug_work,
> +                                           msecs_to_jiffies(1000));
> +                     goto exit;
> +             }
> +     }
>       if (dret) {
>               radeon_connector->detected_by_load = false;
>               radeon_connector_free_edid(connector);
> diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c 
> b/drivers/gpu/drm/radeon/radeon_irq_kms.c
> index 171d3e4..979f3bf 100644
> --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
> +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
> @@ -74,7 +74,7 @@ irqreturn_t radeon_driver_irq_handler_kms(int irq, void 
> *arg)
>   static void radeon_hotplug_work_func(struct work_struct *work)
>   {
>       struct radeon_device *rdev = container_of(work, struct radeon_device,
> -                                               hotplug_work);
> +                                               hotplug_work.work);
>       struct drm_device *dev = rdev->ddev;
>       struct drm_mode_config *mode_config = &dev->mode_config;
>       struct drm_connector *connector;
> @@ -302,7 +302,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
>               }
>       }
>   
> -     INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
> +     INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
>       INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
>       INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
>   
> @@ -310,7 +310,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
>       r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
>       if (r) {
>               rdev->irq.installed = false;
> -             flush_work(&rdev->hotplug_work);
> +             flush_delayed_work(&rdev->hotplug_work);
>               return r;
>       }
>   
> @@ -333,7 +333,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev)
>               rdev->irq.installed = false;
>               if (rdev->msi_enabled)
>                       pci_disable_msi(rdev->pdev);
> -             flush_work(&rdev->hotplug_work);
> +             flush_delayed_work(&rdev->hotplug_work);
>       }
>   }
>   
> diff --git a/drivers/gpu/drm/radeon/radeon_mode.h 
> b/drivers/gpu/drm/radeon/radeon_mode.h
> index 457b026..0aeb3ee 100644
> --- a/drivers/gpu/drm/radeon/radeon_mode.h
> +++ b/drivers/gpu/drm/radeon/radeon_mode.h
> @@ -553,6 +553,7 @@ struct radeon_connector {
>       void *con_priv;
>       bool dac_load_detect;
>       bool detected_by_load; /* if the connection status was determined by 
> load */
> +     bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, 
> but ddc probing failed */
>       uint16_t connector_object_id;
>       struct radeon_hpd hpd;
>       struct radeon_router router;
> diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
> index 97a9048..6244f4e 100644
> --- a/drivers/gpu/drm/radeon/rs600.c
> +++ b/drivers/gpu/drm/radeon/rs600.c
> @@ -813,7 +813,7 @@ int rs600_irq_process(struct radeon_device *rdev)
>               status = rs600_irq_ack(rdev);
>       }
>       if (queue_hotplug)
> -             schedule_work(&rdev->hotplug_work);
> +             schedule_delayed_work(&rdev->hotplug_work, 0);
>       if (queue_hdmi)
>               schedule_work(&rdev->audio_work);
>       if (rdev->msi_enabled) {
> diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
> index 07037e3..fb1a7ec 100644
> --- a/drivers/gpu/drm/radeon/si.c
> +++ b/drivers/gpu/drm/radeon/si.c
> @@ -6848,7 +6848,7 @@ restart_ih:
>       if (queue_dp)
>               schedule_work(&rdev->dp_work);
>       if (queue_hotplug)
> -             schedule_work(&rdev->hotplug_work);
> +             schedule_delayed_work(&rdev->hotplug_work, 0);
>       if (queue_thermal && rdev->pm.dpm_enabled)
>               schedule_work(&rdev->pm.dpm.thermal.work);
>       rdev->ih.rptr = rptr;

Reply via email to