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