@@ -356,8 +356,6 @@ nouveau_display_hpd_work(struct work_struct *work)
356356 pm_runtime_get_sync (drm -> dev -> dev );
357357
358358 drm_helper_hpd_irq_event (drm -> dev );
359- /* enable polling for external displays */
360- drm_kms_helper_poll_enable (drm -> dev );
361359
362360 pm_runtime_mark_last_busy (drm -> dev -> dev );
363361 pm_runtime_put_sync (drm -> dev -> dev );
@@ -380,15 +378,29 @@ nouveau_display_acpi_ntfy(struct notifier_block *nb, unsigned long val,
380378{
381379 struct nouveau_drm * drm = container_of (nb , typeof (* drm ), acpi_nb );
382380 struct acpi_bus_event * info = data ;
381+ int ret ;
383382
384383 if (!strcmp (info -> device_class , ACPI_VIDEO_CLASS )) {
385384 if (info -> type == ACPI_VIDEO_NOTIFY_PROBE ) {
386- /*
387- * This may be the only indication we receive of a
388- * connector hotplug on a runtime suspended GPU,
389- * schedule hpd_work to check.
390- */
391- schedule_work (& drm -> hpd_work );
385+ ret = pm_runtime_get (drm -> dev -> dev );
386+ if (ret == 1 || ret == - EACCES ) {
387+ /* If the GPU is already awake, or in a state
388+ * where we can't wake it up, it can handle
389+ * it's own hotplug events.
390+ */
391+ pm_runtime_put_autosuspend (drm -> dev -> dev );
392+ } else if (ret == 0 ) {
393+ /* This may be the only indication we receive
394+ * of a connector hotplug on a runtime
395+ * suspended GPU, schedule hpd_work to check.
396+ */
397+ NV_DEBUG (drm , "ACPI requested connector reprobe\n" );
398+ schedule_work (& drm -> hpd_work );
399+ pm_runtime_put_noidle (drm -> dev -> dev );
400+ } else {
401+ NV_WARN (drm , "Dropped ACPI reprobe event due to RPM error: %d\n" ,
402+ ret );
403+ }
392404
393405 /* acpi-video should not generate keypresses for this */
394406 return NOTIFY_BAD ;
@@ -412,6 +424,11 @@ nouveau_display_init(struct drm_device *dev)
412424 if (ret )
413425 return ret ;
414426
427+ /* enable connector detection and polling for connectors without HPD
428+ * support
429+ */
430+ drm_kms_helper_poll_enable (dev );
431+
415432 /* enable hotplug interrupts */
416433 drm_connector_list_iter_begin (dev , & conn_iter );
417434 nouveau_for_each_non_mst_connector_iter (connector , & conn_iter ) {
@@ -426,7 +443,7 @@ nouveau_display_init(struct drm_device *dev)
426443}
427444
428445void
429- nouveau_display_fini (struct drm_device * dev , bool suspend )
446+ nouveau_display_fini (struct drm_device * dev , bool suspend , bool runtime )
430447{
431448 struct nouveau_display * disp = nouveau_display (dev );
432449 struct nouveau_drm * drm = nouveau_drm (dev );
@@ -451,6 +468,9 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
451468 }
452469 drm_connector_list_iter_end (& conn_iter );
453470
471+ if (!runtime )
472+ cancel_work_sync (& drm -> hpd_work );
473+
454474 drm_kms_helper_poll_disable (dev );
455475 disp -> fini (dev );
456476}
@@ -640,11 +660,11 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
640660 }
641661 }
642662
643- nouveau_display_fini (dev , true);
663+ nouveau_display_fini (dev , true, runtime );
644664 return 0 ;
645665 }
646666
647- nouveau_display_fini (dev , true);
667+ nouveau_display_fini (dev , true, runtime );
648668
649669 list_for_each_entry (crtc , & dev -> mode_config .crtc_list , head ) {
650670 struct nouveau_framebuffer * nouveau_fb ;
0 commit comments