The recent "inteldrm suspend/resume regression" thread pointed out
that suspend/resume was quite horribly broken and only worked somewhat
if you didn't heavily use the "3D" acceleration stuff.  Here's a diff
that should fix most of the problems, by making sure userland programs
are properly blocked if they try to use drm while we're suspending or
resuming the machine.

I would like to see this diff tested some more by people who actually
use all that eye candy.  The thing to watch for is hangs when you try
to suspend your machine.

Thanks,

Mark

P.S. This seems to make hibernation (ZZZ) work with both inteldrm(4)
and radeondrm(4) on my t400.


Index: drmP.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/drmP.h,v
retrieving revision 1.169
diff -u -p -r1.169 drmP.h
--- drmP.h      9 Mar 2014 07:42:29 -0000       1.169
+++ drmP.h      12 Mar 2014 21:38:43 -0000
@@ -785,6 +785,10 @@ struct drm_device {
        bus_dma_tag_t                   dmat;
        bus_space_tag_t                 bst;
 
+       struct mutex    quiesce_mtx;
+       int             quiesce;
+       int             quiesce_count;
+
        char              *unique;      /* Unique identifier: e.g., busid  */
        int               unique_len;   /* Length of unique field          */
        
Index: drm_drv.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/drm_drv.c,v
retrieving revision 1.124
diff -u -p -r1.124 drm_drv.c
--- drm_drv.c   9 Mar 2014 07:42:29 -0000       1.124
+++ drm_drv.c   12 Mar 2014 21:38:43 -0000
@@ -63,8 +63,12 @@ int   drm_lastclose(struct drm_device *);
 void    drm_attach(struct device *, struct device *, void *);
 int     drm_probe(struct device *, void *, void *);
 int     drm_detach(struct device *, int);
+void    drm_quiesce(struct drm_device *);
+void    drm_wakeup(struct drm_device *);
+int     drm_activate(struct device *, int);
 int     drmprint(void *, const char *);
 int     drmsubmatch(struct device *, void *, void *);
+int     drm_do_ioctl(struct drm_device *, int, u_long, caddr_t);
 int     drm_dequeue_event(struct drm_device *, struct drm_file *, size_t,
             struct drm_pending_event **);
 
@@ -212,6 +216,7 @@ drm_attach(struct device *parent, struct
 
        rw_init(&dev->dev_lock, "drmdevlk");
        mtx_init(&dev->event_lock, IPL_TTY);
+       mtx_init(&dev->quiesce_mtx, IPL_NONE);
 
        TAILQ_INIT(&dev->maplist);
        SPLAY_INIT(&dev->files);
@@ -293,9 +298,47 @@ drm_detach(struct device *self, int flag
        return 0;
 }
 
+void
+drm_quiesce(struct drm_device *dev)
+{
+       mtx_enter(&dev->quiesce_mtx);
+       dev->quiesce = 1;
+       while (dev->quiesce_count > 0) {
+               msleep(&dev->quiesce_count, &dev->quiesce_mtx,
+                   PZERO, "drmqui", 0);
+       }
+       mtx_leave(&dev->quiesce_mtx);
+}
+
+void
+drm_wakeup(struct drm_device *dev)
+{
+       mtx_enter(&dev->quiesce_mtx);
+       dev->quiesce = 0;
+       wakeup(&dev->quiesce);
+       mtx_leave(&dev->quiesce_mtx);
+}
+
+int
+drm_activate(struct device *self, int act)
+{
+       struct drm_device *dev = (struct drm_device *)self;
+
+       switch (act) {
+       case DVACT_QUIESCE:
+               drm_quiesce(dev);
+               break;
+       case DVACT_WAKEUP:
+               drm_wakeup(dev);
+               break;
+       }
+
+       return (0);
+}
+
 struct cfattach drm_ca = {
        sizeof(struct drm_device), drm_probe, drm_attach,
-       drm_detach
+       drm_detach, drm_activate
 };
 
 struct cfdriver drm_cd = {
@@ -540,20 +583,13 @@ done:
        return (retcode);
 }
 
-/* drmioctl is called whenever a process performs an ioctl on /dev/drm.
- */
 int
-drmioctl(dev_t kdev, u_long cmd, caddr_t data, int flags, 
-    struct proc *p)
+drm_do_ioctl(struct drm_device *dev, int minor, u_long cmd, caddr_t data)
 {
-       struct drm_device *dev = drm_get_device_from_kdev(kdev);
        struct drm_file *file_priv;
 
-       if (dev == NULL)
-               return ENODEV;
-
        DRM_LOCK();
-       file_priv = drm_find_file_by_minor(dev, minor(kdev));
+       file_priv = drm_find_file_by_minor(dev, minor);
        DRM_UNLOCK();
        if (file_priv == NULL) {
                DRM_ERROR("can't find authenticator\n");
@@ -715,6 +751,34 @@ drmioctl(dev_t kdev, u_long cmd, caddr_t
                return (EINVAL);
 }
 
+/* drmioctl is called whenever a process performs an ioctl on /dev/drm.
+ */
+int
+drmioctl(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+       struct drm_device *dev = drm_get_device_from_kdev(kdev);
+       int error;
+
+       if (dev == NULL)
+               return ENODEV;
+
+       mtx_enter(&dev->quiesce_mtx);
+       while (dev->quiesce)
+               msleep(&dev->quiesce, &dev->quiesce_mtx, PZERO, "drmioc", 0);
+       dev->quiesce_count++;
+       mtx_leave(&dev->quiesce_mtx);
+
+       error = drm_do_ioctl(dev, minor(kdev), cmd, data);
+
+       mtx_enter(&dev->quiesce_mtx);
+       dev->quiesce_count--;
+       if (dev->quiesce)
+               wakeup(&dev->quiesce);
+       mtx_leave(&dev->quiesce_mtx);
+
+       return (error);
+}
+
 int
 drmread(dev_t kdev, struct uio *uio, int ioflag)
 {
@@ -1224,10 +1288,26 @@ drm_fault(struct uvm_faultinfo *ufi, vad
                return(VM_PAGER_ERROR);
        }
 
+       mtx_enter(&dev->quiesce_mtx);
+       if (dev->quiesce) {
+               mtx_leave(&dev->quiesce_mtx);
+               uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj, NULL);
+               return(VM_PAGER_OK);
+       }
+       dev->quiesce_count++;
+       mtx_leave(&dev->quiesce_mtx);
+
        /* Call down into driver to do the magic */
        ret = dev->driver->gem_fault(obj, ufi, entry->offset + (vaddr -
            entry->start), vaddr, pps, npages, centeridx,
            access_type, flags);
+
+       mtx_enter(&dev->quiesce_mtx);
+       dev->quiesce_count--;
+       if (dev->quiesce)
+               wakeup(&dev->quiesce);
+       mtx_leave(&dev->quiesce_mtx);
+
        return (ret);
 }
 
Index: i915/i915_drv.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_drv.c,v
retrieving revision 1.63
diff -u -p -r1.63 i915_drv.c
--- i915/i915_drv.c     23 Feb 2014 09:36:52 -0000      1.63
+++ i915/i915_drv.c     12 Mar 2014 21:38:43 -0000
@@ -1113,24 +1113,29 @@ inteldrm_detach(struct device *self, int
 }
 
 int
-inteldrm_activate(struct device *arg, int act)
+inteldrm_activate(struct device *self, int act)
 {
-       struct inteldrm_softc   *dev_priv = (struct inteldrm_softc *)arg;
-       struct drm_device       *dev = (struct drm_device *)dev_priv->drmdev;
+       struct inteldrm_softc *dev_priv = (struct inteldrm_softc *)self;
+       struct drm_device *dev = (struct drm_device *)dev_priv->drmdev;
+       int rv = 0;
 
        switch (act) {
        case DVACT_QUIESCE:
+               rv = config_activate_children(self, act);
                i915_drm_freeze(dev);
                break;
        case DVACT_SUSPEND:
                break;
+       case DVACT_RESUME:
+               break;
        case DVACT_WAKEUP:
                i915_drm_thaw(dev);
                intel_fb_restore_mode(dev);
+               rv = config_activate_children(self, act);
                break;
        }
 
-       return (0);
+       return (rv);
 }
 
 struct cfattach inteldrm_ca = {
Index: radeon/radeon_kms.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/radeon/radeon_kms.c,v
retrieving revision 1.24
diff -u -p -r1.24 radeon_kms.c
--- radeon/radeon_kms.c 25 Feb 2014 00:03:38 -0000      1.24
+++ radeon/radeon_kms.c 12 Mar 2014 21:38:43 -0000
@@ -750,12 +750,14 @@ radeondrm_attachhook(void *xsc)
 }
 
 int
-radeondrm_activate_kms(struct device *arg, int act)
+radeondrm_activate_kms(struct device *self, int act)
 {
-       struct radeon_device *rdev = (struct radeon_device *)arg;
+       struct radeon_device *rdev = (struct radeon_device *)self;
+       int rv = 0;
 
        switch (act) {
        case DVACT_QUIESCE:
+               rv = config_activate_children(self, act);
                radeon_suspend_kms(rdev->ddev);
                break;
        case DVACT_SUSPEND:
@@ -764,10 +766,11 @@ radeondrm_activate_kms(struct device *ar
                break;
        case DVACT_WAKEUP:
                radeon_resume_kms(rdev->ddev);
+               rv = config_activate_children(self, act);
                break;
        }
 
-       return (0);
+       return (rv);
 }
 
 /**

Reply via email to