Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread Timo Myyrä
Mark Kettenis mark.kette...@xs4all.nl writes:

 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.h9 Mar 2014 07:42:29 -   1.169
 +++ drmP.h12 Mar 2014 21:38:43 -
 @@ -785,6 +785,10 @@ struct drm_device {
   bus_dma_tag_t   dmat;
   bus_space_tag_t bst;
  
 + struct mutexquiesce_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 -   1.124
 +++ drm_drv.c 12 Mar 2014 21:38:43 -
 @@ -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), 

Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread Mark Kettenis
 Date: Wed, 12 Mar 2014 22:54:06 +0100 (CET)
 From: Mark Kettenis mark.kette...@xs4all.nl
 
 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.

Here's a slightly better diff that should eleminate a (largely
theoretical) deadlock.  If you didn't test yet, try this version
instead.

Index: drmP.h
===
RCS file: /home/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 -   1.169
+++ drmP.h  12 Mar 2014 22:06:11 -
@@ -785,6 +785,10 @@ struct drm_device {
bus_dma_tag_t   dmat;
bus_space_tag_t bst;
 
+   struct mutexquiesce_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: /home/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 -   1.124
+++ drm_drv.c   13 Mar 2014 09:25:38 -
@@ -63,8 +63,12 @@ int   drm_lastclose(struct drm_device *);
 voiddrm_attach(struct device *, struct device *, void *);
 int drm_probe(struct device *, void *, void *);
 int drm_detach(struct device *, int);
+voiddrm_quiesce(struct drm_device *);
+voiddrm_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 

Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread Gregor Best
On Thu, Mar 13, 2014 at 10:31:18AM +0100, Mark Kettenis wrote:
  [...]
  P.S. This seems to make hibernation (ZZZ) work with both inteldrm(4)
  and radeondrm(4) on my t400.
 
 Here's a slightly better diff that should eleminate a (largely
 theoretical) deadlock.  If you didn't test yet, try this version
 instead.
 [...]

Suspend (to RAM) and resume works fine here with

vga1 at pci0 dev 2 function 0 Intel GM965 Video rev 0x0c

Couldn't test hibernate yet because my system has root on a softraid
crypto device and the swap is outside the crypto area.

-- 
Gregor Best



Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread Gregor Best
On Thu, Mar 13, 2014 at 11:16:42AM +0100, Gregor Best wrote:
 [...]
 Couldn't test hibernate yet because my system has root on a softraid
 crypto device and the swap is outside the crypto area.
 [...]

David gave me a hint on how to hardwire my kernel for swap on sd0b.

With that, hibernate works slowly, but it works. The full hibernate +
resume cycle takes about one or two minutes, which I guess is fine.

I'm not sure whether hibernation working is a direct consequence of this
diff, but I think that's OK since the diff didn't break it either.

--
Gregor Best



Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread Marc Peters
On 03/13/14 10:31, Mark Kettenis wrote:
 Date: Wed, 12 Mar 2014 22:54:06 +0100 (CET)
 From: Mark Kettenis mark.kette...@xs4all.nl

 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.
 
 Here's a slightly better diff that should eleminate a (largely
 theoretical) deadlock.  If you didn't test yet, try this version
 instead.

suspend/resume is working. After waking up, Jira in Chrome is no more
dead slow, as it was before.

Hibernating is not working at all at my T530 (crypto softraid on SSD
with Swap inside the softraid). I don't know, if it was working before,
but i usually use suspend. Maybe my swap partition (16G) is to few for
the RAM, didn't really check yet.

dmesg below.

Marc

dmesg:
OpenBSD 5.5-current (GENERIC.MP) #0: Thu Mar 13 11:14:31 CET 2014

root@trivago-620.trivago.local:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 16845565952 (16065MB)
avail mem = 16388415488 (15629MB)
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 2.7 @ 0xdae9d000 (68 entries)
bios0: vendor LENOVO version G4ET97WW (2.57 ) date 10/17/2013
bios0: LENOVO 24297TG
acpi0 at bios0: rev 2
acpi0: sleep states S0 S3 S4 S5
acpi0: tables DSDT FACP SLIC TCPA SSDT SSDT SSDT HPET APIC MCFG ECDT
FPDT ASF! UEFI UEFI MSDM SSDT SSDT UEFI DBG2
acpi0: wakeup devices LID_(S4) SLPB(S3) IGBE(S4) EXP3(S4) XHCI(S3)
EHC1(S3) EHC2(S3) HDEF(S4)
acpitimer0 at acpi0: 3579545 Hz, 24 bits
acpihpet0 at acpi0: 14318179 Hz
acpimadt0 at acpi0 addr 0xfee0: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz, 2594.58 MHz
cpu0:
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS
cpu0: 256KB 64b/line 8-way L2 cache
cpu0: smt 0, core 0, package 0
mtrr: Pentium Pro MTRR support, 10 var ranges, 88 fixed ranges
cpu0: apic clock running at 99MHz
cpu0: mwait min=64, max=64, C-substates=0.2.1.1.2, IBE
cpu1 at mainbus0: apid 1 (application processor)
cpu1: Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz, 2594.11 MHz
cpu1:
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS
cpu1: 256KB 64b/line 8-way L2 cache
cpu1: smt 1, core 0, package 0
cpu2 at mainbus0: apid 2 (application processor)
cpu2: Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz, 2594.11 MHz
cpu2:
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS
cpu2: 256KB 64b/line 8-way L2 cache
cpu2: smt 0, core 1, package 0
cpu3 at mainbus0: apid 3 (application processor)
cpu3: Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz, 2594.11 MHz
cpu3:
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,POPCNT,DEADLINE,AES,XSAVE,AVX,F16C,RDRAND,NXE,LONG,LAHF,PERF,ITSC,FSGSBASE,SMEP,ERMS
cpu3: 256KB 64b/line 8-way L2 cache
cpu3: smt 1, core 1, package 0
ioapic0 at mainbus0: apid 2 pa 0xfec0, version 20, 24 pins
acpimcfg0 at acpi0 addr 0xf800, bus 0-63
acpiec0 at acpi0
acpiprt0 at acpi0: bus 0 (PCI0)
acpiprt1 at acpi0: bus -1 (PEG_)
acpiprt2 at acpi0: bus 2 (EXP1)
acpiprt3 at acpi0: bus 3 (EXP2)
acpiprt4 at acpi0: bus 4 (EXP3)
acpicpu0 at acpi0: C2, C1, PSS
acpicpu1 at acpi0: C2, C1, PSS
acpicpu2 at acpi0: C2, C1, PSS
acpicpu3 at acpi0: C2, C1, PSS
acpipwrres0 at acpi0: PUBS, resource for XHCI, EHC1, EHC2
acpitz0 at acpi0: critical temperature is 103 degC
acpibtn0 at acpi0: LID_
acpibtn1 at acpi0: SLPB
acpibat0 at acpi0: BAT0 model 45N1001 serial 27100 type LION oem SANYO
acpibat1 at acpi0: BAT1 not present
acpiac0 at acpi0: AC unit online
acpithinkpad0 at acpi0
cpu0: Enhanced SpeedStep 2594 MHz: speeds: 2601, 2600, 2500, 2400, 2300,
2200, 2100, 2000, 1900, 1800, 1700, 1600, 1500, 1400, 1300, 1200 MHz
pci0 at 

Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread David Coppa
On Thu, Mar 13, 2014 at 11:53 AM, Gregor Best g...@ring0.de wrote:
 On Thu, Mar 13, 2014 at 11:16:42AM +0100, Gregor Best wrote:
 [...]
 Couldn't test hibernate yet because my system has root on a softraid
 crypto device and the swap is outside the crypto area.
 [...]

 David gave me a hint on how to hardwire my kernel for swap on sd0b.

 With that, hibernate works slowly, but it works. The full hibernate +
 resume cycle takes about one or two minutes, which I guess is fine.

 I'm not sure whether hibernation working is a direct consequence of this
 diff, but I think that's OK since the diff didn't break it either.

I currently have a regression with hibernate (reboot during resume, it
was working fine before).
I will test tonight if Mark's diff unbreaks it...

Ciao,
David



Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread Mattieu Baptiste
On Thu, Mar 13, 2014 at 12:23 PM, Marc Peters m...@mpeters.org wrote:

 On 03/13/14 10:31, Mark Kettenis wrote:
  Date: Wed, 12 Mar 2014 22:54:06 +0100 (CET)
  From: Mark Kettenis mark.kette...@xs4all.nl
 
  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.
 
  Here's a slightly better diff that should eleminate a (largely
  theoretical) deadlock.  If you didn't test yet, try this version
  instead.

 suspend/resume is working. After waking up, Jira in Chrome is no more
 dead slow, as it was before.

 Hibernating is not working at all at my T530 (crypto softraid on SSD
 with Swap inside the softraid). I don't know, if it was working before,
 but i usually use suspend. Maybe my swap partition (16G) is to few for
 the RAM, didn't really check yet.



This patch also fixes the problem for me. After multiple suspend/resume
cycles, X no longer eats the CPU on my T510 with:

vga1 at pci0 dev 2 function 0 Intel HD Graphics rev 0x02
intagp0 at vga1
agp0 at intagp0: aperture at 0xd000, size 0x1000
inteldrm0 at vga1
drm0 at inteldrm0
inteldrm0: 1366x768





Re: inteldrm/radeondrm suspend/resume diff

2014-03-13 Thread David Coppa
On Thu, Mar 13, 2014 at 12:31 PM, David Coppa dco...@gmail.com wrote:
 On Thu, Mar 13, 2014 at 11:53 AM, Gregor Best g...@ring0.de wrote:
 On Thu, Mar 13, 2014 at 11:16:42AM +0100, Gregor Best wrote:
 [...]
 Couldn't test hibernate yet because my system has root on a softraid
 crypto device and the swap is outside the crypto area.
 [...]

 David gave me a hint on how to hardwire my kernel for swap on sd0b.

 With that, hibernate works slowly, but it works. The full hibernate +
 resume cycle takes about one or two minutes, which I guess is fine.

 I'm not sure whether hibernation working is a direct consequence of this
 diff, but I think that's OK since the diff didn't break it either.

 I currently have a regression with hibernate (reboot during resume, it
 was working fine before).
 I will test tonight if Mark's diff unbreaks it...

I confirm this diff fixed my regression with ZZZ.

Thanks a lot, Mark.
Ciao!
David



inteldrm/radeondrm suspend/resume diff

2014-03-12 Thread Mark Kettenis
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 -   1.169
+++ drmP.h  12 Mar 2014 21:38:43 -
@@ -785,6 +785,10 @@ struct drm_device {
bus_dma_tag_t   dmat;
bus_space_tag_t bst;
 
+   struct mutexquiesce_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 -   1.124
+++ drm_drv.c   12 Mar 2014 21:38:43 -
@@ -63,8 +63,12 @@ int   drm_lastclose(struct drm_device *);
 voiddrm_attach(struct device *, struct device *, void *);
 int drm_probe(struct device *, void *, void *);
 int drm_detach(struct device *, int);
+voiddrm_quiesce(struct drm_device *);
+voiddrm_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);
+