Skip to content

Commit cb5d416

Browse files
Lyudealexdeucher
authored andcommitted
drm/radeon: Retry DDC probing on DVI on failure if we got an HPD interrupt
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. Reviewed-by: Christian König <christian.koenig@amd.com> Signed-off-by: Lyude <cpaul@redhat.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent 81d75a3 commit cb5d416

File tree

10 files changed

+32
-12
lines changed

10 files changed

+32
-12
lines changed

drivers/gpu/drm/radeon/cik.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8472,7 +8472,7 @@ int cik_irq_process(struct radeon_device *rdev)
84728472
if (queue_dp)
84738473
schedule_work(&rdev->dp_work);
84748474
if (queue_hotplug)
8475-
schedule_work(&rdev->hotplug_work);
8475+
schedule_delayed_work(&rdev->hotplug_work, 0);
84768476
if (queue_reset) {
84778477
rdev->needs_reset = true;
84788478
wake_up_all(&rdev->fence_queue);

drivers/gpu/drm/radeon/evergreen.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5344,7 +5344,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
53445344
if (queue_dp)
53455345
schedule_work(&rdev->dp_work);
53465346
if (queue_hotplug)
5347-
schedule_work(&rdev->hotplug_work);
5347+
schedule_delayed_work(&rdev->hotplug_work, 0);
53485348
if (queue_hdmi)
53495349
schedule_work(&rdev->audio_work);
53505350
if (queue_thermal && rdev->pm.dpm_enabled)

drivers/gpu/drm/radeon/r100.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,7 @@ int r100_irq_process(struct radeon_device *rdev)
806806
status = r100_irq_ack(rdev);
807807
}
808808
if (queue_hotplug)
809-
schedule_work(&rdev->hotplug_work);
809+
schedule_delayed_work(&rdev->hotplug_work, 0);
810810
if (rdev->msi_enabled) {
811811
switch (rdev->family) {
812812
case CHIP_RS400:

drivers/gpu/drm/radeon/r600.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4276,7 +4276,7 @@ int r600_irq_process(struct radeon_device *rdev)
42764276
WREG32(IH_RB_RPTR, rptr);
42774277
}
42784278
if (queue_hotplug)
4279-
schedule_work(&rdev->hotplug_work);
4279+
schedule_delayed_work(&rdev->hotplug_work, 0);
42804280
if (queue_hdmi)
42814281
schedule_work(&rdev->audio_work);
42824282
if (queue_thermal && rdev->pm.dpm_enabled)

drivers/gpu/drm/radeon/radeon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2414,7 +2414,7 @@ struct radeon_device {
24142414
struct r600_ih ih; /* r6/700 interrupt ring */
24152415
struct radeon_rlc rlc;
24162416
struct radeon_mec mec;
2417-
struct work_struct hotplug_work;
2417+
struct delayed_work hotplug_work;
24182418
struct work_struct dp_work;
24192419
struct work_struct audio_work;
24202420
int num_crtc; /* number of crtcs */

drivers/gpu/drm/radeon/radeon_connectors.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,13 +1234,32 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
12341234
if (r < 0)
12351235
return connector_status_disconnected;
12361236

1237+
if (radeon_connector->detected_hpd_without_ddc) {
1238+
force = true;
1239+
radeon_connector->detected_hpd_without_ddc = false;
1240+
}
1241+
12371242
if (!force && radeon_check_hpd_status_unchanged(connector)) {
12381243
ret = connector->status;
12391244
goto exit;
12401245
}
12411246

1242-
if (radeon_connector->ddc_bus)
1247+
if (radeon_connector->ddc_bus) {
12431248
dret = radeon_ddc_probe(radeon_connector, false);
1249+
1250+
/* Sometimes the pins required for the DDC probe on DVI
1251+
* connectors don't make contact at the same time that the ones
1252+
* for HPD do. If the DDC probe fails even though we had an HPD
1253+
* signal, try again later */
1254+
if (!dret && !force &&
1255+
connector->status != connector_status_connected) {
1256+
DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n");
1257+
radeon_connector->detected_hpd_without_ddc = true;
1258+
schedule_delayed_work(&rdev->hotplug_work,
1259+
msecs_to_jiffies(1000));
1260+
goto exit;
1261+
}
1262+
}
12441263
if (dret) {
12451264
radeon_connector->detected_by_load = false;
12461265
radeon_connector_free_edid(connector);

drivers/gpu/drm/radeon/radeon_irq_kms.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg)
7474
static void radeon_hotplug_work_func(struct work_struct *work)
7575
{
7676
struct radeon_device *rdev = container_of(work, struct radeon_device,
77-
hotplug_work);
77+
hotplug_work.work);
7878
struct drm_device *dev = rdev->ddev;
7979
struct drm_mode_config *mode_config = &dev->mode_config;
8080
struct drm_connector *connector;
@@ -302,15 +302,15 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
302302
}
303303
}
304304

305-
INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
305+
INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
306306
INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
307307
INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
308308

309309
rdev->irq.installed = true;
310310
r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
311311
if (r) {
312312
rdev->irq.installed = false;
313-
flush_work(&rdev->hotplug_work);
313+
flush_delayed_work(&rdev->hotplug_work);
314314
return r;
315315
}
316316

@@ -333,7 +333,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev)
333333
rdev->irq.installed = false;
334334
if (rdev->msi_enabled)
335335
pci_disable_msi(rdev->pdev);
336-
flush_work(&rdev->hotplug_work);
336+
flush_delayed_work(&rdev->hotplug_work);
337337
}
338338
}
339339

drivers/gpu/drm/radeon/radeon_mode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ struct radeon_connector {
553553
void *con_priv;
554554
bool dac_load_detect;
555555
bool detected_by_load; /* if the connection status was determined by load */
556+
bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */
556557
uint16_t connector_object_id;
557558
struct radeon_hpd hpd;
558559
struct radeon_router router;

drivers/gpu/drm/radeon/rs600.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ int rs600_irq_process(struct radeon_device *rdev)
813813
status = rs600_irq_ack(rdev);
814814
}
815815
if (queue_hotplug)
816-
schedule_work(&rdev->hotplug_work);
816+
schedule_delayed_work(&rdev->hotplug_work, 0);
817817
if (queue_hdmi)
818818
schedule_work(&rdev->audio_work);
819819
if (rdev->msi_enabled) {

drivers/gpu/drm/radeon/si.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6848,7 +6848,7 @@ int si_irq_process(struct radeon_device *rdev)
68486848
if (queue_dp)
68496849
schedule_work(&rdev->dp_work);
68506850
if (queue_hotplug)
6851-
schedule_work(&rdev->hotplug_work);
6851+
schedule_delayed_work(&rdev->hotplug_work, 0);
68526852
if (queue_thermal && rdev->pm.dpm_enabled)
68536853
schedule_work(&rdev->pm.dpm.thermal.work);
68546854
rdev->ih.rptr = rptr;

0 commit comments

Comments
 (0)