Module Name:    src
Committed By:   riastradh
Date:           Sat Oct 15 15:19:28 UTC 2022

Modified Files:
        src/sys/external/bsd/drm2/dist/drm: drm_drv.c drm_ioctl.c
        src/sys/external/bsd/drm2/dist/include/drm: drm_device.h drm_ioctl.h

Log Message:
drm: New mechanism to suspend ioctls during system suspend.

drm drivers must opt into this by calling drm_suspend_ioctl in their
driver suspend routine, and drm_resume_ioctl in their driver resume
routine.

This is a stop-gap measure -- it would be better to fill in the
pm_runtime_* API with new pmf(9) hooks to acquire/release references
to devices for coordinating with suspend/resume, but getting the
details right is tricky, and this stop-gap is enough to get i915
suspend/resume to work reliably on my Kaby Lake laptop.  Rather than
wait until I've got all the details right, let's just go with this
stop-gap for now.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/external/bsd/drm2/dist/drm/drm_drv.c \
    src/sys/external/bsd/drm2/dist/drm/drm_ioctl.c
cvs rdiff -u -r1.10 -r1.11 \
    src/sys/external/bsd/drm2/dist/include/drm/drm_device.h
cvs rdiff -u -r1.4 -r1.5 \
    src/sys/external/bsd/drm2/dist/include/drm/drm_ioctl.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/drm2/dist/drm/drm_drv.c
diff -u src/sys/external/bsd/drm2/dist/drm/drm_drv.c:1.23 src/sys/external/bsd/drm2/dist/drm/drm_drv.c:1.24
--- src/sys/external/bsd/drm2/dist/drm/drm_drv.c:1.23	Sun Jul 17 14:11:18 2022
+++ src/sys/external/bsd/drm2/dist/drm/drm_drv.c	Sat Oct 15 15:19:28 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_drv.c,v 1.23 2022/07/17 14:11:18 riastradh Exp $	*/
+/*	$NetBSD: drm_drv.c,v 1.24 2022/10/15 15:19:28 riastradh Exp $	*/
 
 /*
  * Created: Fri Jan 19 10:48:35 2001 by fa...@acm.org
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.23 2022/07/17 14:11:18 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.24 2022/10/15 15:19:28 riastradh Exp $");
 
 #include <linux/debugfs.h>
 #include <linux/fs.h>
@@ -695,6 +695,12 @@ int drm_dev_init(struct drm_device *dev,
 	mutex_init(&dev->filelist_mutex);
 	mutex_init(&dev->clientlist_mutex);
 	mutex_init(&dev->master_mutex);
+#ifdef __NetBSD__
+	mutex_init(&dev->suspend_lock);
+	DRM_INIT_WAITQUEUE(&dev->suspend_cv, "drmsusp");
+	dev->active_ioctls = 0;
+	dev->suspender = NULL;
+#endif
 
 	dev->sc_monitor_hotplug.smpsw_name = PSWITCH_HK_DISPLAY_CYCLE;
 	dev->sc_monitor_hotplug.smpsw_type = PSWITCH_TYPE_HOTKEY;
@@ -757,6 +763,12 @@ err_pswitch:
 #ifndef __NetBSD__		/* XXX drm sysfs */
 	put_device(dev->dev);
 #endif
+#ifdef __NetBSD__
+	KASSERT(dev->suspender == NULL);
+	KASSERT(dev->active_ioctls == 0);
+	DRM_DESTROY_WAITQUEUE(&dev->suspend_cv);
+	mutex_destroy(&dev->suspend_lock);
+#endif
 	mutex_destroy(&dev->master_mutex);
 	mutex_destroy(&dev->clientlist_mutex);
 	mutex_destroy(&dev->filelist_mutex);
@@ -844,6 +856,13 @@ void drm_dev_fini(struct drm_device *dev
 	put_device(dev->dev);
 #endif
 
+#ifdef __NetBSD__
+	KASSERT(dev->suspender == NULL);
+	KASSERT(dev->active_ioctls == 0);
+	DRM_DESTROY_WAITQUEUE(&dev->suspend_cv);
+	mutex_destroy(&dev->suspend_lock);
+#endif
+
 	mutex_destroy(&dev->master_mutex);
 	mutex_destroy(&dev->clientlist_mutex);
 	mutex_destroy(&dev->filelist_mutex);
Index: src/sys/external/bsd/drm2/dist/drm/drm_ioctl.c
diff -u src/sys/external/bsd/drm2/dist/drm/drm_ioctl.c:1.23 src/sys/external/bsd/drm2/dist/drm/drm_ioctl.c:1.24
--- src/sys/external/bsd/drm2/dist/drm/drm_ioctl.c:1.23	Sat Aug 27 21:24:15 2022
+++ src/sys/external/bsd/drm2/dist/drm/drm_ioctl.c	Sat Oct 15 15:19:28 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_ioctl.c,v 1.23 2022/08/27 21:24:15 riastradh Exp $	*/
+/*	$NetBSD: drm_ioctl.c,v 1.24 2022/10/15 15:19:28 riastradh Exp $	*/
 
 /*
  * Created: Fri Jan  8 09:01:26 1999 by fa...@valinux.com
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: drm_ioctl.c,v 1.23 2022/08/27 21:24:15 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: drm_ioctl.c,v 1.24 2022/10/15 15:19:28 riastradh Exp $");
 
 #include <linux/export.h>
 #include <linux/nospec.h>
@@ -739,6 +739,58 @@ static const struct drm_ioctl_desc drm_i
 
 #define DRM_CORE_IOCTL_COUNT	ARRAY_SIZE( drm_ioctls )
 
+#ifdef __NetBSD__
+/* ioctl suspend/resume */
+
+static void
+drm_ioctl_enter(struct drm_device *dev)
+{
+	int ret __diagused;
+
+	mutex_lock(&dev->suspend_lock);
+	DRM_WAIT_NOINTR_UNTIL(ret, &dev->suspend_cv, &dev->suspend_lock,
+	    dev->suspender == NULL);
+	KASSERTMSG(ret == 0, "error=%d", -ret);
+	dev->active_ioctls++;
+	mutex_unlock(&dev->suspend_lock);
+}
+
+static void
+drm_ioctl_exit(struct drm_device *dev)
+{
+
+	mutex_lock(&dev->suspend_lock);
+	KASSERT(dev->suspender == NULL);
+	if (--dev->active_ioctls == 0)
+		DRM_WAKEUP_ALL(&dev->suspend_cv, &dev->suspend_lock);
+	mutex_unlock(&dev->suspend_lock);
+}
+
+void
+drm_suspend_ioctl(struct drm_device *dev)
+{
+	int ret;
+
+	mutex_lock(&dev->suspend_lock);
+	DRM_WAIT_NOINTR_UNTIL(ret, &dev->suspend_cv, &dev->suspend_lock,
+	    dev->suspender == NULL && dev->active_ioctls == 0);
+	dev->suspender = curlwp;
+	mutex_unlock(&dev->suspend_lock);
+}
+
+void
+drm_resume_ioctl(struct drm_device *dev)
+{
+
+	mutex_lock(&dev->suspend_lock);
+	KASSERT(dev->suspender);
+	KASSERT(dev->active_ioctls == 0);
+	dev->suspender = NULL;
+	DRM_WAKEUP_ALL(&dev->suspend_cv, &dev->suspend_lock);
+	mutex_unlock(&dev->suspend_lock);
+}
+#endif
+
 /**
  * DOC: driver specific ioctls
  *
@@ -805,6 +857,8 @@ long drm_ioctl_kernel(struct file *file,
 	if (unlikely(retcode))
 		return retcode;
 
+	drm_ioctl_enter(dev);
+
 	/* Enforce sane locking for modern driver ioctls. */
 	if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) ||
 	    (flags & DRM_UNLOCKED))
@@ -814,6 +868,9 @@ long drm_ioctl_kernel(struct file *file,
 		retcode = func(dev, kdata, file_priv);
 		mutex_unlock(&drm_global_mutex);
 	}
+
+	drm_ioctl_exit(dev);
+
 	return retcode;
 }
 EXPORT_SYMBOL(drm_ioctl_kernel);
@@ -900,6 +957,7 @@ drm_ioctl(struct file *fp, unsigned long
 		data0 = buf;
 	}
 
+	drm_ioctl_enter(dev);
 	if ((drm_core_check_feature(dev, DRIVER_MODESET) && is_driver_ioctl) ||
 	    ISSET(ioctl->flags, DRM_UNLOCKED)) {
 		/* XXX errno Linux->NetBSD */
@@ -910,6 +968,7 @@ drm_ioctl(struct file *fp, unsigned long
 		error = -(*ioctl->func)(dev, data0, file);
 		mutex_unlock(&drm_global_mutex);
 	}
+	drm_ioctl_exit(dev);
 
 	/* If we used a temporary buffer, copy it back out.  */
 	if (data != data0)

Index: src/sys/external/bsd/drm2/dist/include/drm/drm_device.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drm_device.h:1.10 src/sys/external/bsd/drm2/dist/include/drm/drm_device.h:1.11
--- src/sys/external/bsd/drm2/dist/include/drm/drm_device.h:1.10	Wed Dec 22 12:05:24 2021
+++ src/sys/external/bsd/drm2/dist/include/drm/drm_device.h	Sat Oct 15 15:19:28 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_device.h,v 1.10 2021/12/22 12:05:24 riastradh Exp $	*/
+/*	$NetBSD: drm_device.h,v 1.11 2022/10/15 15:19:28 riastradh Exp $	*/
 
 #ifndef _DRM_DEVICE_H_
 #define _DRM_DEVICE_H_
@@ -12,6 +12,7 @@
 #include <drm/drm_mode_config.h>
 
 #ifdef __NetBSD__
+#include <drm/drm_wait_netbsd.h>
 #include <dev/sysmon/sysmonvar.h>
 #endif
 
@@ -332,6 +333,10 @@ struct drm_device {
 
 #ifdef __NetBSD__
 	struct sysmon_pswitch sc_monitor_hotplug;
+	struct mutex suspend_lock;
+	drm_waitqueue_t suspend_cv;
+	uint64_t active_ioctls;
+	struct lwp *suspender;
 #endif
 
 	/* Everything below here is for legacy driver, never use! */

Index: src/sys/external/bsd/drm2/dist/include/drm/drm_ioctl.h
diff -u src/sys/external/bsd/drm2/dist/include/drm/drm_ioctl.h:1.4 src/sys/external/bsd/drm2/dist/include/drm/drm_ioctl.h:1.5
--- src/sys/external/bsd/drm2/dist/include/drm/drm_ioctl.h:1.4	Sun Dec 19 01:56:08 2021
+++ src/sys/external/bsd/drm2/dist/include/drm/drm_ioctl.h	Sat Oct 15 15:19:28 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: drm_ioctl.h,v 1.4 2021/12/19 01:56:08 riastradh Exp $	*/
+/*	$NetBSD: drm_ioctl.h,v 1.5 2022/10/15 15:19:28 riastradh Exp $	*/
 
 /*
  * Internal Header for the Direct Rendering Manager
@@ -178,6 +178,8 @@ struct drm_ioctl_desc {
 int drm_ioctl_permit(u32 flags, struct drm_file *file_priv);
 #ifdef __NetBSD__
 int drm_ioctl(struct file *, unsigned long, void *);
+void drm_suspend_ioctl(struct drm_device *);
+void drm_resume_ioctl(struct drm_device *);
 #else
 long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
 #endif

Reply via email to