From mryan01@vapre.elision.org  Fri Jul 28 08:16:10 2000
Return-Path: <mryan01@vapre.elision.org>
Received: from vapre.elision.org (r83aap006377.sbo-smr.ma.cable.rcn.com [146.115.122.245])
	by hub.freebsd.org (Postfix) with ESMTP id D557237C27F
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 28 Jul 2000 08:16:08 -0700 (PDT)
	(envelope-from mryan01@vapre.elision.org)
Received: by vapre.elision.org (Postfix, from userid 1000)
	id C176219316; Fri, 28 Jul 2000 11:18:07 -0400 (EDT)
Message-Id: <20000728151807.C176219316@vapre.elision.org>
Date: Fri, 28 Jul 2000 11:18:07 -0400 (EDT)
From: mike ryan <msr+fbsd@elision.org>
Sender: mryan01@vapre.elision.org
To: FreeBSD-gnats-submit@freebsd.org
Subject: [PATCH] resume from suspend breaks pcm
X-Send-Pr-Version: 3.2

>Number:         20255
>Category:       kern
>Synopsis:       [PATCH] resume from suspend breaks pcm
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    cg
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jul 28 08:20:01 PDT 2000
>Closed-Date:    Sun Apr 8 15:07:20 PDT 2001
>Last-Modified:  Sun Apr 08 15:09:36 PDT 2001
>Originator:     mike ryan
>Release:        FreeBSD 4.1-STABLE i386
>Organization:
>Environment:

	sony vaio z505hs laptop with yamaha ds-1e audio.

>Description:

	after resuming from suspend, sound can no longer be played.  any
	attempt to play sound results in "pcm0: play interrupt timeout,
	channel dead" errors.

>How-To-Repeat:

	suspend + resume.

>Fix:

	this patch works for me:

Index: sys/dev/sound/pci/ds1.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/sound/pci/ds1.c,v
retrieving revision 1.8.2.1
diff -c -r1.8.2.1 ds1.c
*** sys/dev/sound/pci/ds1.c	2000/07/19 21:18:45	1.8.2.1
--- sys/dev/sound/pci/ds1.c	2000/07/28 15:05:44
***************
*** 114,119 ****
--- 114,124 ----
  	int		regid, irqid;
  	void		*ih;
  
+ 	u_int32_t	workbase;
+ 	u_int32_t	playctrlbase;
+ 	u_int32_t	recctrlbase;
+ 	u_int32_t	effctrlbase;
+ 
  	u_int32_t *pbase, pbankbase, pbanksize;
  	volatile struct pbank *pbank[2 * 64];
  	volatile struct rbank *rbank;
***************
*** 819,834 ****
  
  	cb = 0;
  	t = buf;
! 	ds_wr(sc, YDSXGR_WORKBASE, sc->ctrlbase + cb, 4);
  	cb += ws;
  	sc->pbase = (u_int32_t *)(t + cb);
  	/* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */
! 	ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->ctrlbase + cb, 4);
  	cb += (64 + 1) * 4;
  	sc->rbank = (struct rbank *)(t + cb);
! 	ds_wr(sc, YDSXGR_RECCTRLBASE, sc->ctrlbase + cb, 4);
  	cb += 2 * 2 * rcs;
! 	ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->ctrlbase + cb, 4);
  	cb += 5 * 2 * ecs;
  
  	sc->pbankbase = sc->ctrlbase + cb;
--- 824,843 ----
  
  	cb = 0;
  	t = buf;
! 	sc->workbase = sc->ctrlbase + cb;
! 	ds_wr(sc, YDSXGR_WORKBASE, sc->workbase, 4);
  	cb += ws;
  	sc->pbase = (u_int32_t *)(t + cb);
  	/* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */
! 	sc->playctrlbase = sc->ctrlbase + cb;
! 	ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->playctrlbase, 4);
  	cb += (64 + 1) * 4;
  	sc->rbank = (struct rbank *)(t + cb);
! 	sc->recctrlbase = sc->ctrlbase + cb;
! 	ds_wr(sc, YDSXGR_RECCTRLBASE, sc->recctrlbase, 4);
  	cb += 2 * 2 * rcs;
! 	sc->effctrlbase = sc->ctrlbase + cb;
! 	ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->effctrlbase, 4);
  	cb += 5 * 2 * ecs;
  
  	sc->pbankbase = sc->ctrlbase + cb;
***************
*** 970,979 ****
--- 979,1039 ----
  	return ENXIO;
  }
  
+ static int
+ ds_pci_suspend(device_t dev)
+ {
+ 	snddev_info *d = device_get_softc(dev);
+ 	struct sc_info *sc = (struct sc_info *)d->devinfo;
+ 
+ 	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
+ 	ds_enadsp(sc, 0);
+ 
+ 	return 0;
+ }
+ 
+ static int
+ ds_pci_resume(device_t dev)
+ {
+ 	int i;
+ 	u_int32_t r;
+ 	snddev_info *d = device_get_softc(dev);
+ 	struct sc_info *sc = (struct sc_info *)d->devinfo;
+ 
+ 	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4);
+ 	ds_enadsp(sc, 0);
+ 	ds_wr(sc, YDSXGR_MODE, 0x00010000, 4);
+ 	ds_wr(sc, YDSXGR_MODE, 0x00000000, 4);
+ 	ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4);
+ 	ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4);
+ 	ds_wr(sc, YDSXGR_WORKBASE, 0x00000000, 4);
+ 	ds_wr(sc, YDSXGR_WORKBASE, sc->workbase, 4);
+ 	ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4);
+ 	ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->playctrlbase, 4);
+ 	ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4);
+ 	ds_wr(sc, YDSXGR_RECCTRLBASE, sc->recctrlbase, 4);
+ 	ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4);
+ 	ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->effctrlbase, 4);
+ 	r = ds_rd(sc, YDSXGR_GLOBALCTRL, 2);
+ 	ds_wr(sc, YDSXGR_GLOBALCTRL, r & ~0x0007, 2);
+ 
+ 	for (i=0; i < sc->pchn; i++)
+ 		chn_resetbuf(sc->pch[i].channel);
+ 	for (i=0; i < sc->rchn; i++)
+ 		chn_resetbuf(sc->rch[i].channel);
+ 
+ 	ds_enadsp(sc, 1);
+ 	mixer_reinit(d);
+ 	ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff, 4);
+ 
+ 	return 0;
+ }
+ 
  static device_method_t ds1_methods[] = {
  	/* Device interface */
  	DEVMETHOD(device_probe,		ds_pci_probe),
  	DEVMETHOD(device_attach,	ds_pci_attach),
+ 	DEVMETHOD(device_suspend,	ds_pci_suspend),
+ 	DEVMETHOD(device_resume,	ds_pci_resume),
  
  	{ 0, 0 }
  };

>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->cg 
Responsible-Changed-By: billf 
Responsible-Changed-When: Fri Jul 28 15:15:05 PDT 2000 
Responsible-Changed-Why:  
over to the pcm maintainer. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=20255 

From: David Jones <dej@ox.org>
To: freebsd-gnats-submit@FreeBSD.org, msr+fbsd@elision.org
Cc:  
Subject: Re: kern/20255: [PATCH] resume from suspend breaks pcm
Date: Mon, 07 Aug 2000 21:12:36 -0400

 The "channel dead" problem is not limited to suspend and resume.
 
 I can produce it using my VIA82C686 driver by running "xgalaga" from the
 ports collection.
 
 From the code, the channel is marked dead if the driver is unable to
 make progress writing data for more than one second.  My driver was
 using 16K buffers divided into two 8K halves.  At 8 kbps, there could be
 a race between the timeout in the write routine and the buffer playing. 
 Therefore, I changed my code to use smaller buffers, so now I have four
 4K buffers.  However, I still occasionally get this error.
 
 In FreeBSD 4.0, xgalaga's sounds lagged the action often by a second or
 more.  I believe that the application may not be writing correctly to
 the audio device.  If this is the case, then to mark the channel dead is
 not appropriate behavior, since a reboot is required to reset the
 system.  One can envision a denial-of-service attack whose effect is to
 mute the target computer until it is rebooted.
 
 I will attempt to patch my kernel to reset the "Dead" bit when the
 device is closed, to get around the immediate DOS, and to enable further
 experimentation.  I may be able to determine the sequence of actions
 that provoke the problem.  In any event, to have suspend/resume handlers
 in the low-level drivers themselves is not a good solution to a problem
 that was introduced at a higher layer.
 

From: mike ryan <msr@elision.org>
To: David Jones <dej@ox.org>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/20255: [PATCH] resume from suspend breaks pcm
Date: Mon, 7 Aug 2000 23:06:47 -0400

 On Mon, Aug 07, 2000 at 09:12:36PM -0400, David Jones wrote:
 > The "channel dead" problem is not limited to suspend and resume.
 > 
 > I can produce it using my VIA82C686 driver by running "xgalaga"
 > from the ports collection.
 
 same effect, different cause.
 
 > From the code, the channel is marked dead if the driver is unable
 > to make progress writing data for more than one second.
 
 it doesn't matter whether or not audio is playing when the machine
 is suspended -- after resume, all audio output will fail unless
 certain registers on the device itself are reset.
 
 > In any event, to have suspend/resume handlers in the low-level
 > drivers themselves is not a good solution to a problem that was
 > introduced at a higher layer.
 
 we're encountering different problems here.  the bios on these
 particular laptops just don't do a good job of restoring state after
 a resume.  see kern/18261 and kern/18756 for similar problems (and
 fixes) with the uhci and fxp devices.
 
 it's possible that a fix for the bug you describe would alleviate
 the need for the chn_resetbuf() calls, but the register resets
 appear to be mandatory.
 
State-Changed-From-To: open->closed 
State-Changed-By: greid 
State-Changed-When: Sun Apr 8 15:07:20 PDT 2001 
State-Changed-Why:  
Patch from misc/20891 committed 

http://www.freebsd.org/cgi/query-pr.cgi?pr=20255 
>Unformatted:
