diff mbox series

[2/2] drm/nouveau: Prevent redundant connector probes from ACPI

Message ID 20180731005835.21032-2-lyude@redhat.com (mailing list archive)
State New, archived
Headers show
Series [1/2] drm/nouveau: Print debug message on ACPI probe event | expand

Commit Message

Lyude Paul July 31, 2018, 12:58 a.m. UTC
On the Lenovo P50 I've been working on, ACPI notifications for hotplugs
always seem happen even while the GPU has it's hotplugs enabled. This
means that we're uselessly scheduling two connector probes every time we
get a hotplug.

Since we can't unregister the acpi handler without causing userspace to
start getting mysterious keypresses from the ACPI_VIDEO_REPROBE events
that are meant for us, simply add a member to nouveau_drm that can be
used to enable/disable our ACPI event handler from being able to
schedule connector probes on it's own.

Signed-off-by: Lyude Paul <lyude@redhat.com>
---
 drivers/gpu/drm/nouveau/nouveau_display.c | 40 +++++++++++++++--------
 drivers/gpu/drm/nouveau/nouveau_display.h |  4 +--
 drivers/gpu/drm/nouveau/nouveau_drm.c     |  4 +--
 drivers/gpu/drm/nouveau/nouveau_drv.h     |  1 +
 4 files changed, 32 insertions(+), 17 deletions(-)

Comments

kernel test robot July 31, 2018, 10:33 a.m. UTC | #1
Hi Lyude,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v4.18-rc7 next-20180727]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Lyude-Paul/drm-nouveau-Print-debug-message-on-ACPI-probe-event/20180731-150343
config: arm-multi_v7_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.2.0 make.cross ARCH=arm 

All errors (new ones prefixed by >>):

   In file included from include/linux/kernel.h:10:0,
                    from include/linux/list.h:9,
                    from include/linux/agp_backend.h:33,
                    from include/drm/drmP.h:35,
                    from drivers/gpu/drm/nouveau/nouveau_display.c:28:
   drivers/gpu/drm/nouveau/nouveau_display.c: In function 'nouveau_display_init':
>> drivers/gpu/drm/nouveau/nouveau_display.c:431:16: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
     WRITE_ONCE(drm->acpi_hpd_enabled, false);
                   ^
   include/linux/compiler.h:275:17: note: in definition of macro 'WRITE_ONCE'
     union { typeof(x) __val; char __c[1]; } __u = \
                    ^
>> drivers/gpu/drm/nouveau/nouveau_display.c:431:16: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
     WRITE_ONCE(drm->acpi_hpd_enabled, false);
                   ^
   include/linux/compiler.h:276:30: note: in definition of macro 'WRITE_ONCE'
      { .__val = (__force typeof(x)) (val) }; \
                                 ^
>> drivers/gpu/drm/nouveau/nouveau_display.c:431:16: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
     WRITE_ONCE(drm->acpi_hpd_enabled, false);
                   ^
   include/linux/compiler.h:277:22: note: in definition of macro 'WRITE_ONCE'
     __write_once_size(&(x), __u.__c, sizeof(x)); \
                         ^
>> drivers/gpu/drm/nouveau/nouveau_display.c:431:16: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
     WRITE_ONCE(drm->acpi_hpd_enabled, false);
                   ^
   include/linux/compiler.h:277:42: note: in definition of macro 'WRITE_ONCE'
     __write_once_size(&(x), __u.__c, sizeof(x)); \
                                             ^
   drivers/gpu/drm/nouveau/nouveau_display.c: In function 'nouveau_display_fini':
   drivers/gpu/drm/nouveau/nouveau_display.c:458:17: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
      WRITE_ONCE(drm->acpi_hpd_enabled, true);
                    ^
   include/linux/compiler.h:275:17: note: in definition of macro 'WRITE_ONCE'
     union { typeof(x) __val; char __c[1]; } __u = \
                    ^
   drivers/gpu/drm/nouveau/nouveau_display.c:458:17: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
      WRITE_ONCE(drm->acpi_hpd_enabled, true);
                    ^
   include/linux/compiler.h:276:30: note: in definition of macro 'WRITE_ONCE'
      { .__val = (__force typeof(x)) (val) }; \
                                 ^
   drivers/gpu/drm/nouveau/nouveau_display.c:458:17: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
      WRITE_ONCE(drm->acpi_hpd_enabled, true);
                    ^
   include/linux/compiler.h:277:22: note: in definition of macro 'WRITE_ONCE'
     __write_once_size(&(x), __u.__c, sizeof(x)); \
                         ^
   drivers/gpu/drm/nouveau/nouveau_display.c:458:17: error: 'struct nouveau_drm' has no member named 'acpi_hpd_enabled'
      WRITE_ONCE(drm->acpi_hpd_enabled, true);
                    ^
   include/linux/compiler.h:277:42: note: in definition of macro 'WRITE_ONCE'
     __write_once_size(&(x), __u.__c, sizeof(x)); \
                                             ^

vim +431 drivers/gpu/drm/nouveau/nouveau_display.c

   404	
   405	int
   406	nouveau_display_init(struct drm_device *dev, bool runtime)
   407	{
   408		struct nouveau_display *disp = nouveau_display(dev);
   409		struct nouveau_drm *drm = nouveau_drm(dev);
   410		struct drm_connector *connector;
   411		struct drm_connector_list_iter conn_iter;
   412		int ret;
   413	
   414		ret = disp->init(dev);
   415		if (ret)
   416			return ret;
   417	
   418		/* enable hotplug interrupts */
   419		drm_connector_list_iter_begin(dev, &conn_iter);
   420		nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
   421			struct nouveau_connector *conn = nouveau_connector(connector);
   422			nvif_notify_get(&conn->hpd);
   423		}
   424		drm_connector_list_iter_end(&conn_iter);
   425	
   426		/* disable ACPI hotplug handling to prevent duplicate connector
   427		 * probes
   428		 * FIXME: make sure that WRITE_ONCE() implies a store barrier
   429		 * beforehand
   430		 */
 > 431		WRITE_ONCE(drm->acpi_hpd_enabled, false);
   432	
   433		/* enable flip completion events */
   434		nvif_notify_get(&drm->flip);
   435		return ret;
   436	}
   437	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox series

Patch

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index b2a93e3fa67b..b80226c87487 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -382,13 +382,16 @@  nouveau_display_acpi_ntfy(struct notifier_block *nb, unsigned long val,
 
 	if (!strcmp(info->device_class, ACPI_VIDEO_CLASS)) {
 		if (info->type == ACPI_VIDEO_NOTIFY_PROBE) {
-			/*
-			 * This may be the only indication we receive of a
-			 * connector hotplug on a runtime suspended GPU,
-			 * schedule hpd_work to check.
-			 */
-			NV_DEBUG(drm, "ACPI requested connector probe\n");
-			schedule_work(&drm->hpd_work);
+			if (READ_ONCE(drm->acpi_hpd_enabled)) {
+				/*
+				 * This may be the only indication we receive
+				 * of a connector hotplug on a runtime
+				 * suspended GPU, schedule hpd_work to check.
+				 */
+				NV_DEBUG(drm,
+					 "ACPI requested connector probe\n");
+				schedule_work(&drm->hpd_work);
+			}
 
 			/* acpi-video should not generate keypresses for this */
 			return NOTIFY_BAD;
@@ -400,7 +403,7 @@  nouveau_display_acpi_ntfy(struct notifier_block *nb, unsigned long val,
 #endif
 
 int
-nouveau_display_init(struct drm_device *dev)
+nouveau_display_init(struct drm_device *dev, bool runtime)
 {
 	struct nouveau_display *disp = nouveau_display(dev);
 	struct nouveau_drm *drm = nouveau_drm(dev);
@@ -420,13 +423,20 @@  nouveau_display_init(struct drm_device *dev)
 	}
 	drm_connector_list_iter_end(&conn_iter);
 
+	/* disable ACPI hotplug handling to prevent duplicate connector
+	 * probes
+	 * FIXME: make sure that WRITE_ONCE() implies a store barrier
+	 * beforehand
+	 */
+	WRITE_ONCE(drm->acpi_hpd_enabled, false);
+
 	/* enable flip completion events */
 	nvif_notify_get(&drm->flip);
 	return ret;
 }
 
 void
-nouveau_display_fini(struct drm_device *dev, bool suspend)
+nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime)
 {
 	struct nouveau_display *disp = nouveau_display(dev);
 	struct nouveau_drm *drm = nouveau_drm(dev);
@@ -443,6 +453,10 @@  nouveau_display_fini(struct drm_device *dev, bool suspend)
 	/* disable flip completion events */
 	nvif_notify_put(&drm->flip);
 
+	/* let ACPI handle hotplugs since we won't have them enabled */
+	if (runtime)
+		WRITE_ONCE(drm->acpi_hpd_enabled, true);
+
 	/* disable hotplug interrupts */
 	drm_connector_list_iter_begin(dev, &conn_iter);
 	nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) {
@@ -619,11 +633,11 @@  nouveau_display_suspend(struct drm_device *dev, bool runtime)
 			}
 		}
 
-		nouveau_display_fini(dev, true);
+		nouveau_display_fini(dev, true, runtime);
 		return 0;
 	}
 
-	nouveau_display_fini(dev, true);
+	nouveau_display_fini(dev, true, runtime);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct nouveau_framebuffer *nouveau_fb;
@@ -656,7 +670,7 @@  nouveau_display_resume(struct drm_device *dev, bool runtime)
 	int ret;
 
 	if (drm_drv_uses_atomic_modeset(dev)) {
-		nouveau_display_init(dev);
+		nouveau_display_init(dev, runtime);
 		if (disp->suspend) {
 			drm_atomic_helper_resume(dev, disp->suspend);
 			disp->suspend = NULL;
@@ -689,7 +703,7 @@  nouveau_display_resume(struct drm_device *dev, bool runtime)
 			NV_ERROR(drm, "Could not pin/map cursor.\n");
 	}
 
-	nouveau_display_init(dev);
+	nouveau_display_init(dev, runtime);
 
 	/* Force CLUT to get re-loaded during modeset */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index 54aa7c3fa42d..473411120225 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -61,8 +61,8 @@  nouveau_display(struct drm_device *dev)
 
 int  nouveau_display_create(struct drm_device *dev);
 void nouveau_display_destroy(struct drm_device *dev);
-int  nouveau_display_init(struct drm_device *dev);
-void nouveau_display_fini(struct drm_device *dev, bool suspend);
+int  nouveau_display_init(struct drm_device *dev, bool runtime);
+void nouveau_display_fini(struct drm_device *dev, bool suspend, bool runtime);
 int  nouveau_display_suspend(struct drm_device *dev, bool runtime);
 void nouveau_display_resume(struct drm_device *dev, bool runtime);
 int  nouveau_display_vblank_enable(struct drm_device *, unsigned int);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index c7ec86d6c3c9..65dc5b5cf6ce 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -574,7 +574,7 @@  nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 		goto fail_dispctor;
 
 	if (dev->mode_config.num_crtc) {
-		ret = nouveau_display_init(dev);
+		ret = nouveau_display_init(dev, false);
 		if (ret)
 			goto fail_dispinit;
 	}
@@ -629,7 +629,7 @@  nouveau_drm_unload(struct drm_device *dev)
 	nouveau_debugfs_fini(drm);
 
 	if (dev->mode_config.num_crtc)
-		nouveau_display_fini(dev, false);
+		nouveau_display_fini(dev, false, false);
 	nouveau_display_destroy(dev);
 
 	nouveau_bios_takedown(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 6e1acaec3400..22e70e72ec8b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -201,6 +201,7 @@  struct nouveau_drm {
 	int fbcon_new_state;
 #ifdef CONFIG_ACPI
 	struct notifier_block acpi_nb;
+	bool acpi_hpd_enabled;
 #endif
 
 	/* power management */