* Trouble with sound/mips/au1x00.c AC97 driver @ 2007-03-07 10:49 Freddy Spierenburg 2007-03-09 7:22 ` Marco Braga 0 siblings, 1 reply; 15+ messages in thread From: Freddy Spierenburg @ 2007-03-07 10:49 UTC (permalink / raw) To: Charles Eidsness; +Cc: linux-mips [-- Attachment #1: Type: text/plain, Size: 3414 bytes --] Hi Charles, I'm experiencing strange behaviour with the sound/mips/au1x00.c AC97 driver. I'm using kernel 2.6.16, but 2.6.20 gives me the same results. When I load the driver sometimes (frequently enough that it's a serious problem) I do not get all 38 simple mixer controls. Sometimes I'm missing one or more controls, but in a more rare situation it also happens that a control holds the wrong min/max values. And in an even more rare situation I get the error below while loading the driver: AC'97 0 access error (not audio or modem codec) I have tried to track it down and it all boils down to the snd_au1000_ac97_read() routine, I think. When I try to debug the problem, I see that most of the time the res and val variables compared in snd_ac97_try_bit() from sound/pci/ac97/ac97_codec.c do not appear to be equal. Hence the missing controls. It looks to me that snd_au1000_ac97_read() is not returning a value expected. When I look at the snd_au1000_ac97_read() implementation it looks good to me. I've read the AU1100 Processor Data Book and your routine does exactly the thing needed to read data from the AC97 controller. I've also inspected the whole thing a little bit and I never receive a 'au1000 AC97: AC97 command read timeout'. Never is a command still pending before you stop try to poll for the sane situation and never is an answer not yet received from the codec before you stop polling for it. And the poll values are never close to the 0x5000 max you specify. For the latter test (the test if the data is available) I have also checked if the data is available right away (i==0). This happens rarely and does not cause trouble if it happens. So there is not much that I understand that goes wrong in this routine. I might be wrong of course. Any insight from real kernel hackers? I really do get the feeling that it's a hardware thing. But my hardware engineer doesn't yet believe that. And I'm afraid he has sound (sic :) reasoning. I've tested this code on two different platforms. The first is an official AMD SYRAH DbAu1100 board with a Sigmatel STAC9752T audio codec and the second is our own Balvenie board (based on the DbAu1100 design) with an Wolfson WM9705 audio codec. Both platforms experience the same problems. We have also checked all the timings to and from the codec with an oscilloscope and they are up to spec. Nothing strange happening over there. What I've also done is play a sound file constantly over the course of several days. During that playing I constantly did some muting/unmuting of the 'Master', 'Master Mono' and 'Headphone' output. I connected some speakers and the small shell-script I wrote rotated the audio in a nice loop around the speakers. This happened like every second or so. No error messages from the amixer utility over that course of days and no error message from aplay whatsoever. I have also never heard any strange glitch in the playing of audio, but if only a few samples are missing or tampered it might be impossible to hear. Anyway, does anyone have ever experienced this trouble and have any clue what might causes it? -- $ cat ~/.signature Freddy Spierenburg <freddy@dusktilldawn.nl> http://freddy.snarl.nl/ GnuPG: 0x7941D1E1=C948 5851 26D2 FA5C 39F1 E588 6F17 FD5D 7941 D1E1 $ # Please read http://www.ietf.org/rfc/rfc2015.txt before complain! [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-07 10:49 Trouble with sound/mips/au1x00.c AC97 driver Freddy Spierenburg @ 2007-03-09 7:22 ` Marco Braga 2007-03-09 10:33 ` Freddy Spierenburg [not found] ` <45F350E9.3020208@cooper-street.com> 0 siblings, 2 replies; 15+ messages in thread From: Marco Braga @ 2007-03-09 7:22 UTC (permalink / raw) To: Freddy Spierenburg; +Cc: Charles Eidsness, linux-mips [-- Attachment #1: Type: text/plain, Size: 159 bytes --] Hello Freddy, I have exactly the same problem with a custom board based on an Alchemy Au1500, kernel 2.6.17.14 from linux-mips.org No solution at the moment. [-- Attachment #2: Type: text/html, Size: 240 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-09 7:22 ` Marco Braga @ 2007-03-09 10:33 ` Freddy Spierenburg 2007-03-10 13:20 ` Marco Braga [not found] ` <45F350E9.3020208@cooper-street.com> 1 sibling, 1 reply; 15+ messages in thread From: Freddy Spierenburg @ 2007-03-09 10:33 UTC (permalink / raw) To: Marco Braga; +Cc: linux-mips [-- Attachment #1: Type: text/plain, Size: 4434 bytes --] Hi Marco, On Fri, Mar 09, 2007 at 08:22:22AM +0100, Marco Braga wrote: > I have exactly the same problem with a custom board based on an Alchemy > Au1500, kernel 2.6.17.14 from linux-mips.org > No solution at the moment. The only solution I have yet is a small shell-script to load the kernel driver and checks if all 38 controls are available. If not it removes the driver and loads it again. Most of the times it works right away and it's a very rare case that it takes the script 8 loads to get all controls. I did around 143.000 tests and 120.000 times it loaded correctly the first time, 20.000 the seconds time, it faded gradually after that and only one time it took 8 times. But unfortunately, this work-around is far from perfect. It's possible for the driver to load with all 38 controls, but wrong control data. Let's say the CD volume control has a normal range that is 0 - 31, and it happens sometimes the range is fucked up. Let's say 0 - 15. Again snd_au1000_ac97_read() to blame. Anyway, you don't want that, for obvious reason! So as a more robust work-around, I'm almost finished with a small Python program that reads /var/lib/alsa/asound.state (the saved mixer values) and checks these against the values received from the ALSA layer. I've patched pyalsaaudio-0.2 (the most usable Python ALSA bindings IMHO) a little bit, and can now ask the ALSA layer all relevant information needed. When it's completely finished I shall mail the patches to the maintainer in the hope he'll include them. And if finished I'm willing to share the small Python program too, if anyone asks. But what does this gives us? In the long run not much, to be honoust! Like I told in my first email, I did also do a lot of other tests and if the driver is loaded correctly things do work well. So in the short run this is a good workable solution for me. But in the long run the kernel driver needs te be fixed of course. And unfortunately I still consider myself a fool when it comes to kernel programming. I have already decided to dive into this a little bit in my spare time, but I'm afraid I lack the right kernel knowledge when it comes to solve this issue. Charles Eidsnes nicely answered my email with some tips, but also told me he has other priorities than to dive into this. If one is up to the challange to fix this he is willing to answer some questions, but he's not actively involved with mips-linux anymore. Anyway, here is his tip to look into: On Wed, Mar 07, 2007 at 06:48:05PM -0500, Charles Eidsness wrote: > I'm not sure what could cause this issue. Given your results on > different hardware I think you're right in assuming that it's > not a hardware issue (at least not with your AC'97 Codec). It > kind of seems like a S/W timing issue. All that I can think of > to suggest it to try adding some delays during the read cycle > and see if that helps. It may be that there is some lag between > when the processor says the data register has data, and when it > really has data. You could also try to implement an interrupt > based read, you may have better luck with it than I did. I gave > up because it was taking me too long to get it to work, and I > didn't mind the extra over-head of a polled read. Sounds like some good advice to look into. Althought I'm a little bit confused about why the AC97 controller would state that information is available, when it is really not yet available. Sounds like plain wrong to me. But then again, do not forget that I'm the fool without a lot of knowledge on the subject again. :) Anyway, to end up this long, long writing. Within a couple of hours I'm of to the south of France to do some serious snowboarding, so I will not look into this for like a little more than a week. After that I will finish the Python work-around and in my spare time shall dive into a real solution, but not with much hope of fixing it for real. Thanks for your reply and maybe with this little bit of extra information some kernel hacker has his druthers and fixes the bloody thing. If not just wait what I come up with, but please don't hold your breath to it. -- $ cat ~/.signature Freddy Spierenburg <freddy@dusktilldawn.nl> http://freddy.snarl.nl/ GnuPG: 0x7941D1E1=C948 5851 26D2 FA5C 39F1 E588 6F17 FD5D 7941 D1E1 $ # Please read http://www.ietf.org/rfc/rfc2015.txt before complain! [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-09 10:33 ` Freddy Spierenburg @ 2007-03-10 13:20 ` Marco Braga 0 siblings, 0 replies; 15+ messages in thread From: Marco Braga @ 2007-03-10 13:20 UTC (permalink / raw) To: Freddy Spierenburg; +Cc: linux-mips [-- Attachment #1: Type: text/plain, Size: 1142 bytes --] Hello Freddy, Friday I've had some time to explore the problem. My current experience is with an Au1500 based custom board. I've compiled the ALSA modules for the integrated AC97 in kernel 2.6.17.14. I've still not noticed the problem with the missing controls, but my most frequent issue is with the "AC'97 0 access error (not audio or modem codec)" error message. Notice that when this message is issued the module is not loaded, so I have to reload it. At the moment the only solution for this problem is to force a device reset during the board setup. Strange enough, it is exactly the same thing done in the module with the lines: /* Initialise Au1000's AC'97 Control Block */ au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE; udelay(10); au1000->ac97_ioport->cntrl = AC97C_CE; udelay(10); Perhaps the delays are not correct, and doing them in the board setup (at kernel start) leaves enought time for the clocks to stabilize (just guessing). Basically you have to play with bits 0 and 1 in the device control register (0xB000 0010). I'll check the issue again next monday, but I am for sure not a kernel guru. [-- Attachment #2: Type: text/html, Size: 1362 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <45F350E9.3020208@cooper-street.com>]
[parent not found: <d459bb380703120157wb3dde00p4c232e300e82fd3d@mail.gmail.com>]
* Re: Trouble with sound/mips/au1x00.c AC97 driver [not found] ` <d459bb380703120157wb3dde00p4c232e300e82fd3d@mail.gmail.com> @ 2007-03-12 9:59 ` Marco Braga 2007-03-12 10:39 ` Domen Puncer [not found] ` <45F5DC73.9060004@cooper-street.com> 0 siblings, 2 replies; 15+ messages in thread From: Marco Braga @ 2007-03-12 9:59 UTC (permalink / raw) To: linux-mips; +Cc: charles, Freddy Spierenburg [-- Attachment #1: Type: text/plain, Size: 2664 bytes --] Hello, I've added to: "snd_au1000_ac97_new" the lines: au1000->ac97_ioport->config = AC97C_SG | AC97C_SYNC; udelay(100); au1000->ac97_ioport->config = 0x0; after the cold reset, as you suggested. Sadly this did not solve the problem. It seems that the only solution I have at the moment is to add a longer delay between hard reset and warm reset. I've changed the "udelay(10)" to a "mdelay(250)" (I know, it is a huge delay) but now the module is loaded perfectly every time. Now I'll try to reduce the delay and find the min. I don't know if this issue is related to our board or if you can explain it. What about the spin_lock_irqsave stuff? Do you suggest to leave them in or it is better to return to the old simple spin_lock? 2007/3/12, Marco Braga <marco.braga@gmail.com>: > > Hi Charles, just a quick note: the "spin_lock_irqrestore" should be > "spin_unlock_irqrestore". Anyway, the changed does not solve my problem > (I've also tried the change in au1000_ac97_write). > As you see in the logs at the end of the email, it seems that module > loading has random results. I've managed to follow the problem to line 606, > when it calls "snd_ac97_mixer". This call often returns an error. > > I'll try with the resets now.. > > > -- LOG: ------------------------------------------------ > > # modprobe snd_au1x00 > [ 584.704000] AC'97 0 does not respond - RESET > [ 584.717000] AC'97 0 access error (not audio or modem codec) > insmod: cannot insert '/lib/modules/2.6.17.14/kernel/sound/mips/snd- > au1x00.ko': > Success (13): Success > modprobe: failed to load module snd_au1x00 > > # modprobe snd_au1x00 > [ 1345.967000] AC'97 0 does not respond - RESET > [ 1345.980000] AC'97 0 access error (not audio or modem codec) > insmod: cannot insert '/lib/modules/2.6.17.14/kernel/sound/mips/snd- > au1x00.ko': > Success (13): Success > modprobe: failed to load module snd_au1x00 > > # modprobe snd_au1x00 > [ 1351.211000] AC'97 0 does not respond - RESET > [ 1351.224000] AC'97 0 access error (not audio or modem codec) > insmod: cannot insert '/lib/modules/2.6.17.14/kernel/sound/mips/snd- > au1x00.ko': > Success (13): Success > modprobe: failed to load module snd_au1x00 > > # modprobe snd_au1x00 > [ 1355.471000] AC'97 0 analog subsections not ready > [ 1355.497000] ALSA AC97: Driver Initialized > > # modprobe snd_au1x00 > [ 1361.837000] ALSA AC97: Driver Initialized > > # modprobe snd_au1x00 > [ 1365.403000] AC'97 0 analog subsections not ready > [ 1365.428000] ALSA AC97: Driver Initialized > > # modprobe snd_au1x00 > [ 1369.037000] ALSA AC97: Driver Initialized > > # modprobe snd_au1x00 > [ 1372.374000] ALSA AC97: Driver Initialized > > > [-- Attachment #2: Type: text/html, Size: 3169 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-12 9:59 ` Marco Braga @ 2007-03-12 10:39 ` Domen Puncer 2007-03-12 13:09 ` Marco Braga [not found] ` <45F5DC73.9060004@cooper-street.com> 1 sibling, 1 reply; 15+ messages in thread From: Domen Puncer @ 2007-03-12 10:39 UTC (permalink / raw) To: Marco Braga; +Cc: linux-mips On 12/03/07 10:59 +0100, Marco Braga wrote: > Hello, > > I've added to: "snd_au1000_ac97_new" the lines: > > au1000->ac97_ioport->config = AC97C_SG | AC97C_SYNC; > udelay(100); > au1000->ac97_ioport->config = 0x0; > > after the cold reset, as you suggested. Sadly this did not solve the > problem. > > It seems that the only solution I have at the moment is to add a longer > delay between hard reset and warm reset. I've changed the "udelay(10)" to a > "mdelay(250)" (I know, it is a huge delay) but now the module is loaded > perfectly every time. Now I'll try to reduce the delay and find the min. > I don't know if this issue is related to our board or if you can explain it. > Hi! It might be ignorance on my part, but aren't au_sync()'s needed here? Domen ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-12 10:39 ` Domen Puncer @ 2007-03-12 13:09 ` Marco Braga 2007-03-12 15:35 ` Sergei Shtylyov 0 siblings, 1 reply; 15+ messages in thread From: Marco Braga @ 2007-03-12 13:09 UTC (permalink / raw) To: Domen Puncer; +Cc: linux-mips [-- Attachment #1: Type: text/plain, Size: 211 bytes --] 2007/3/12, Domen Puncer <domen.puncer@telargo.com>: > > It might be ignorance on my part, but aren't au_sync()'s needed here? My ignorance too.. What's au_sync()? Something to writeback/invalidate the cache? [-- Attachment #2: Type: text/html, Size: 492 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-12 13:09 ` Marco Braga @ 2007-03-12 15:35 ` Sergei Shtylyov 2007-03-13 0:43 ` Ralf Baechle 0 siblings, 1 reply; 15+ messages in thread From: Sergei Shtylyov @ 2007-03-12 15:35 UTC (permalink / raw) To: Marco Braga; +Cc: Domen Puncer, linux-mips Hello. Marco Braga wrote: > 2007/3/12, Domen Puncer <domen.puncer@telargo.com>: >> It might be ignorance on my part, but aren't au_sync()'s needed here? > My ignorance too.. What's au_sync()? Something to writeback/invalidate the > cache? It's "memory barrier" (SYNC instruction). WBR, Sergei ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-12 15:35 ` Sergei Shtylyov @ 2007-03-13 0:43 ` Ralf Baechle 2007-03-13 1:00 ` Andrew Dyer 0 siblings, 1 reply; 15+ messages in thread From: Ralf Baechle @ 2007-03-13 0:43 UTC (permalink / raw) To: Sergei Shtylyov; +Cc: Marco Braga, Domen Puncer, linux-mips On Mon, Mar 12, 2007 at 06:35:04PM +0300, Sergei Shtylyov wrote: > >>It might be ignorance on my part, but aren't au_sync()'s needed here? > > >My ignorance too.. What's au_sync()? Something to writeback/invalidate the > >cache? > > It's "memory barrier" (SYNC instruction). For the general MIPS case (Alchemy may provide guarantees I don't know of) a SYNC instruction is not sufficient to ensure that a write has actually been reached by the device. It may just like on PCI take a read from the same device again: au1000->ac97_ioport->config = AC97C_SG | AC97C_SYNC; au1000->ac97_ioport->config; udelay(100); au1000->ac97_ioport->config = 0x0; to ensure that all preceding write have actually made it. That also means that any use of the SYNC instruction may well be just an attempt to paper over a bug. Ralf ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-13 0:43 ` Ralf Baechle @ 2007-03-13 1:00 ` Andrew Dyer 2007-03-13 1:09 ` Ralf Baechle 0 siblings, 1 reply; 15+ messages in thread From: Andrew Dyer @ 2007-03-13 1:00 UTC (permalink / raw) To: Ralf Baechle; +Cc: Sergei Shtylyov, Marco Braga, Domen Puncer, linux-mips Ralf Baechle wrote: > For the general MIPS case (Alchemy may provide guarantees I don't know of) > a SYNC instruction is not sufficient to ensure that a write has actually > been reached by the device. It may just like on PCI take a read from the > same device again: I just looked it up. Section 2.4.5 of the Alchemy Au1550 datasheet says that a SYNC is guaranteed to commit the write buffer to memory. Whoever is looking at this should also pay attention to the CCA bits in the TLB mapping the registers (Section 2.3.6 of the manual) or the fixed regions (depending on the VA used) to make sure that merging and gathering are turned off. -- Andrew Dyer <adyer@righthandtech.com> Sr. Engineer RightHand Technologies, Inc. 6545 N. Olmsted Ave. Chicago, IL 60631 (773) 774-7600 x111 ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-13 1:00 ` Andrew Dyer @ 2007-03-13 1:09 ` Ralf Baechle 2007-03-13 8:44 ` Marco Braga 0 siblings, 1 reply; 15+ messages in thread From: Ralf Baechle @ 2007-03-13 1:09 UTC (permalink / raw) To: Andrew Dyer; +Cc: Sergei Shtylyov, Marco Braga, Domen Puncer, linux-mips On Mon, Mar 12, 2007 at 08:00:58PM -0500, Andrew Dyer wrote: > I just looked it up. > > Section 2.4.5 of the Alchemy Au1550 datasheet says that a SYNC is > guaranteed to commit the write buffer to memory. > > Whoever is looking at this should also pay attention to the CCA bits in > the TLB mapping the registers (Section 2.3.6 of the manual) or the fixed > regions (depending on the VA used) to make sure that merging and > gathering are turned off. MIPS does does no merging / gathering for uncached accesses. KSEG1 addresses are uncached. Ralf ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-13 1:09 ` Ralf Baechle @ 2007-03-13 8:44 ` Marco Braga 0 siblings, 0 replies; 15+ messages in thread From: Marco Braga @ 2007-03-13 8:44 UTC (permalink / raw) To: linux-mips [-- Attachment #1: Type: text/plain, Size: 943 bytes --] Hello everyone, 2007/3/13, Charles Eidsness <charles@cooper-street.com>: > > I wonder if the AC'97 Controller has to be up for at least one frame > before issuing the cold reset. Each frame is 20.8us, you could try > setting that delay to 25us instead of 500ms. I've tested this. I've changed my delay to a "udelay(25)". It didn't work. Sergei on the mailing list had a good suggestion as well. You could try > replacing every udelay with an au_sync_udelay, and each mdelay with an > au_sync_delay. I've done this too. Still no success. > You could even try dropping in an au_sync at the end of > the snd_au1000_ac97_new function. No success, but I've found that I can reduce the delay to at least 200ms. I'll try with lower values. I hope that my inexperience (and perhapes errors while testing) don't lead you to wrong conclusions, but from the trials I've done the only change that at the moment works for me is the 200ms delay. [-- Attachment #2: Type: text/html, Size: 1704 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
[parent not found: <45F5DC73.9060004@cooper-street.com>]
[parent not found: <d459bb380703130143w7c98e1cchdbdae6cb9a7ac7ce@mail.gmail.com>]
[parent not found: <45F71FFD.202@cooper-street.com>]
* Re: Trouble with sound/mips/au1x00.c AC97 driver [not found] ` <45F71FFD.202@cooper-street.com> @ 2007-03-13 23:12 ` Marco Braga 2007-03-15 8:04 ` Marco Braga 0 siblings, 1 reply; 15+ messages in thread From: Marco Braga @ 2007-03-13 23:12 UTC (permalink / raw) To: linux-mips [-- Attachment #1: Type: text/plain, Size: 656 bytes --] Dear Charles, I do agree that my "fix" is not worth an official patch, not only because it is inelegant but because we haven't found the exact cause of the problem. I think at the moment we need to collect more reports, just to know if I am the only one experiencing this issue. Tomorrow I'll post a message with a small cut&paste of the piece of code I've changed, as a reference if some other person encounters the same problem. As a final notice, the 200ms delay is not noticeable at all. The overall boot time is almost the same, and the installing time of the module is less than a second. I'd like to thank you all people for the support and help. [-- Attachment #2: Type: text/html, Size: 707 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver 2007-03-13 23:12 ` Marco Braga @ 2007-03-15 8:04 ` Marco Braga 0 siblings, 0 replies; 15+ messages in thread From: Marco Braga @ 2007-03-15 8:04 UTC (permalink / raw) To: linux-mips [-- Attachment #1: Type: text/plain, Size: 529 bytes --] As promised, this is my change: linux/sound/mips/au1x00.c, function "snd_au1000_ac97_new": ... /* Initialise Au1000's AC'97 Control Block */ au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE; udelay(10); au1000->ac97_ioport->cntrl = AC97C_CE; /* Original delay 10us */ /* udelay(10); */ /* New delay 200ms */ mdelay(200); /* Initialise External CODEC -- cold reset */ au1000->ac97_ioport->config = AC97C_RESET; udelay(10); au1000->ac97_ioport->config = 0x0; mdelay(5); ... [-- Attachment #2: Type: text/html, Size: 844 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Trouble with sound/mips/au1x00.c AC97 driver [not found] ` <45F5DC73.9060004@cooper-street.com> [not found] ` <d459bb380703130143w7c98e1cchdbdae6cb9a7ac7ce@mail.gmail.com> @ 2007-04-16 14:47 ` Freddy Spierenburg 1 sibling, 0 replies; 15+ messages in thread From: Freddy Spierenburg @ 2007-04-16 14:47 UTC (permalink / raw) To: Jaroslav Kysela; +Cc: Marco Braga, Charles Eidsness, linux-mips [-- Attachment #1.1: Type: text/plain, Size: 1610 bytes --] Hi Jaroslav, Please find attached a patch that fixes some known problems currently part of the au1x00 ALSA audio driver. Signed-off-by: Freddy Spierenburg <freddy@dusktilldawn.nl> Below is a small time explanation of why the patch is needed. On Mon, Mar 12, 2007 at 07:04:19PM -0400, Charles Eidsness wrote: > I wonder if the AC'97 Controller has to be up for at least one > frame before issuing the cold reset. Each frame is 20.8us, you > could try setting that delay to 25us instead of 500ms. The 10us delay indeed is not enough. 25us gives way better results. Combining it with... > Sergei on the mailing list had a good suggestion as well. You could try > replacing every udelay with an au_sync_udelay, and each mdelay with an > au_sync_delay. ...Sergei his suggestion, and more importantly... > I think that spin_lock_irqsave stuff might fix the problem that Freddy > has ...replacing spin_lock() by spin_lock_irqsave() gives me good results. Still not perfectly, but way better than it was. Using the Python audio-script I've attached to this email I've loaded and unloaded the driver 4033 times and it failed 6 times on me. Failing means one control is missing or a control features the wrong settings. If this happens the Python script tries to load the driver again and in all of my tests succeeds right away. -- $ cat ~/.signature Freddy Spierenburg <freddy@dusktilldawn.nl> http://freddy.snarl.nl/ GnuPG: 0x7941D1E1=C948 5851 26D2 FA5C 39F1 E588 6F17 FD5D 7941 D1E1 $ # Please read http://www.ietf.org/rfc/rfc2015.txt before complain! [-- Attachment #1.2: au1x00.patch --] [-- Type: text/x-diff, Size: 1955 bytes --] diff -Naur linux-2.6.20.orig/sound/mips/au1x00.c linux-2.6.20/sound/mips/au1x00.c --- linux-2.6.20.orig/sound/mips/au1x00.c 2007-02-04 20:22:45.000000000 +0000 +++ linux-2.6.20/sound/mips/au1x00.c 2007-04-16 14:04:39.000000000 +0000 @@ -496,8 +496,9 @@ u32 volatile cmd; u16 volatile data; int i; + unsigned long flags; - spin_lock(&au1000->ac97_lock); + spin_lock_irqsave(&au1000->ac97_lock, flags); /* would rather use the interupt than this polling but it works and I can't get the interupt driven case to work efficiently */ for (i = 0; i < 0x5000; i++) @@ -520,7 +521,7 @@ } data = au1000->ac97_ioport->cmd & 0xffff; - spin_unlock(&au1000->ac97_lock); + spin_unlock_irqrestore(&au1000->ac97_lock, flags); return data; @@ -533,8 +534,9 @@ struct snd_au1000 *au1000 = ac97->private_data; u32 cmd; int i; + unsigned long flags; - spin_lock(&au1000->ac97_lock); + spin_lock_irqsave(&au1000->ac97_lock, flags); /* would rather use the interupt than this polling but it works and I can't get the interupt driven case to work efficiently */ for (i = 0; i < 0x5000; i++) @@ -547,7 +549,7 @@ cmd &= ~AC97C_READ; cmd |= ((u32) val << AC97C_WD_BIT); au1000->ac97_ioport->cmd = cmd; - spin_unlock(&au1000->ac97_lock); + spin_unlock_irqrestore(&au1000->ac97_lock, flags); } static int __devinit @@ -577,15 +579,15 @@ /* Initialise Au1000's AC'97 Control Block */ au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE; - udelay(10); + au_sync_udelay(10); au1000->ac97_ioport->cntrl = AC97C_CE; - udelay(10); + au_sync_udelay(25); /* Initialise External CODEC -- cold reset */ au1000->ac97_ioport->config = AC97C_RESET; - udelay(10); + au_sync_udelay(10); au1000->ac97_ioport->config = 0x0; - mdelay(5); + au_sync_delay(5); /* Initialise AC97 middle-layer */ if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0) [-- Attachment #1.3: audio --] [-- Type: text/plain, Size: 12471 bytes --] #!/usr/bin/python # # Nice script to load/unload the audio kernel driver. It checks as much # controls as possible. It does this by comparing the configured values to the # values restored after loading the driver. It reads the configured values from # /var/lib/alsa/asound.state and tries to load the driver again if any control # does not hold it's configured value or is even missing. # # Usage: audio start|stop # # Freddy Spierenburg <freddy@dusktilldawn.nl> Mon, 16 Apr 2007 16:39:45 +0200 import sys, os, re, string, alsaaudio # This is the class definition for the base control type. All derived controls # share this information. class Control: # The class constructor method. def __init__(self, storage): # Get the name for this control. self.name = storage['name'].replace('\'', '') # Initialize the value list. self.value = [] # Does this control has more than one value? if int(storage['comment.count']) > 1: # Yes, run through all the values. for index in range(int(storage['comment.count'])): # Save every value in our value list. self.value.append(storage['value.' + str(index)]) else: # No, just store this one value in the list. self.value.append(storage['value']) # A nice debug information method. def show(self): # Show the name for this control. print self.name, ':' # Run through all the values for this control. for v in self.value: # Show every value. print 'value =', v # This is the class definition for the boolean control type. class BooleanFactory: def Create(self,storage): return Boolean(storage) class Boolean(Control): # The class constructor method. def __init__(self, storage): # Start the constructor for the base class. Control.__init__(self, storage) # The test method to see if the control is initialized correctly. We test to see # if the current boolean value is equal to the one configured. def error(self): # Get the real name for the control. All control names should be stripped from the # named strings, except the one holding a '-' character. control = self.name if control.count('-') == 0: control = control.replace('Playback Switch', '').replace('Switch', '') control = control.strip() try: # Get a reference to the control mixer = alsaaudio.Mixer(control) # Find the mute state for this control. mute = mixer.getmute() # Return true if the current boolean value is not equal to the configured value. return not ((mute[0] == 0 and self.value[0] == 'true') or (mute[0] == 1 and self.value[0] == 'false')) except alsaaudio.ALSAAudioError: # An error probably indicates a missing control. This is bad! return True # This is the class definition for the integer control type. class IntegerFactory: def Create(self,storage): return Integer(storage) class Integer(Control): # The class constructor method. def __init__(self, storage): # Start the constructor for the base class. Control.__init__(self, storage) # An integer type holds a range. Split it into a minimum and # maximum field. field = string.split(re.sub("'", '', storage['comment.range']), '-') # Save the minimum value. self.minimum = int(field[0]) # Save the maximum value. self.maximum = int(field[1]) # A nice debug information method. def show(self): # Show the information for the base class. Control.show(self) # Show the configured minimum and maximum value for the range. print 'minimum =', self.minimum, 'maximum =', self.maximum # The test method to see if the control is initialized correctly. We test to see # if the range value is like expected and the current volume setting is like it # is configured. def error(self): # Get the real name for the control. control = self.name.replace('Playback Volume', '').replace('Volume', '').strip() try: # Get a reference to the control. mixer = alsaaudio.Mixer(control) except alsaaudio.ALSAAudioError: # An error indicates a missing control. This is bad! return True # Find the range for this control. rng = mixer.getrange() # Check if the current range value is like expected. rangeOK = (rng[0] == self.minimum and rng[1] == self.maximum) # Find the current volume value. volume = mixer.getvolume() # Expect this volume value to be good by default. volumeOK = True # Run through the found volume values. for index in range(len(volume)): # We get the percentage volume value from the ALSA layer, but # we need the index value. Calculate the index value from the # percentage. volume[index] = round(volume[index] * self.maximum / 100.0) # Is the current volume value not equal to the configured value? if volume[index] != int(self.value[index]): # Yes, unfortunately there is something wrong. Set our flag! volumeOK = False # And stop checking right away. We're out of luck anyway! break # Return true if the range or volume is not ok! return not (rangeOK and volumeOK) # This is the class definition for the enumerated control type. class EnumeratedFactory: def Create(self,storage): return Enumerated(storage) class Enumerated(Control): # The class constructor method. def __init__(self, storage): # Start the constructor for the base class. Control.__init__(self, storage) # A nice debug information method. def show(self): # Show only the information for the base class. Control.show(self) # The test method to see if the control is initialized correctly. We test to # see if the current enumerated type value for the control is equal to the # configured value. def error(self): try: # Get a reference to the control. mixer = alsaaudio.Mixer(self.name) # Find the enumerated type for this control. enum = mixer.getenum() # Return true if the current enumerated type is not equal to the # configured one. return not (enum[0] == self.value[0].replace('\'', '')) except alsaaudio.ALSAAudioError: # An error probably indicates a missing control. This is bad! return True # We do not yet do much with the IEC958 control type. class IEC958Factory: def Create(self,storage): return IEC958(storage) class IEC958(Control): def __init__(self, storage): Control.__init__(self, storage) # The factories is a dictionary of control types we recognize and handle. factories = { 'BOOLEAN': BooleanFactory(), 'INTEGER': IntegerFactory(), 'ENUMERATED': EnumeratedFactory(), 'IEC958': IEC958Factory() } # The list of all the controls that should be available. If we need to # check them they hold the value true, false if we choose to ignore them. controlsAvailableList = { "'Master Playback Switch'": True, "'Master Playback Volume'": True, "'Headphone Playback Switch'": True, "'Headphone Playback Volume'": True, "'Master Mono Playback Switch'": True, "'Master Mono Playback Volume'": True, "'PC Speaker Playback Switch'": True, "'PC Speaker Playback Volume'": True, "'Phone Playback Switch'": True, "'Phone Playback Volume'": True, "'Mic Playback Switch'": True, "'Mic Playback Volume'": True, "'Mic Boost (+20dB)'": True, "'Line Playback Switch'": True, "'Line Playback Volume'": True, "'CD Playback Switch'": True, "'CD Playback Volume'": True, "'Video Playback Switch'": True, "'Aux Playback Switch'": True, "'PCM Playback Switch'": True, "'PCM Playback Volume'": True, "'Capture Source'": False, "'Capture Switch'": False, "'Capture Volume'": True, "'PCM Out Path & Mute'": True, "'3D Control - Switch'": True, "'Mono Output Select'": True, "'Mic Select'": True, "'3D Control - Center'": True, "'3D Control - Depth'": True, "'IEC958 Playback Con Mask'": False, "'IEC958 Playback Pro Mask'": False, "'IEC958 Playback Default'": False, "'IEC958 Playback Switch'": False, "'IEC958 Playback AC97-SPSA'": False, "'Front Playback Volume'": True, "'Front Playback Switch'": True, "'External Amplifier'": True } # The routine to stop the audio driver. def driverStop(): os.system('/sbin/rmmod snd-au1x00 > /dev/null 2>&1') # The routine to start the audio driver. def driverStart(): # The start of a control block is marked by the next reg-exp. start = re.compile('control') # The end of a control block is marked by the next reg-exp. end = re.compile('\s+}$') # We only add stuff to our storage when we are inside a control block. process = False # Initialize our temporary storage to be empty at the start. storage = {} # Initialize our list of controls to be empty at the start.. controls = [] # Open the ALSA configuration file. file=open('/var/lib/alsa/asound.state', 'r') # Process every line read from the file. for line in file.readlines(): # What kind of line is this? if start.search(line): # It marks the start of a control block. Start processing. process = True # Clear our temporary storage before we begin. storage.clear() elif end.search(line): # It marks the end of a control block. Stop processing. process = False # Is this one of the controls we would like to check? if controlsAvailableList.has_key(storage['name']) and controlsAvailableList[storage['name']]: # Yes! Find out by means of the control type, what kind of object to create. factory = factories[storage['comment.type']] # Add the object type to our list of controls. controls.append(factory.Create(storage)) elif process: # We are in the middle of processing and this line is data we need to # store in our object. First split the line in a name and value pair. The # first space is seen as the separator. field = string.split(string.strip(line), ' ', 1) # Put the name and value pair inside our temporary storage. storage[field[0]]=field[1] # Close the file. file.close() # To see if the driver is loaded is marked by the next reg-exp. driver = re.compile('^snd_au1x00') # By default we expect our driver not to load. loaded = False # Continue to load the driver untill it is loaded. while not loaded: # Run the command to find out which kernel drivers are loaded. stdout = os.popen('/bin/lsmod') # Read the output from the previous command. output = stdout.read() # Is our driver loaded? if driver.search(output): # Yes, mark that we've loaded the driver. loaded = True else: # No, so try to load it ourselves. loaded = not os.system('(/sbin/modprobe snd-au1x00 && /etc/init.d/alsa-utils start) > /dev/null 2>&1') # If we're loaded we are going to check if everything is ok. ok = loaded # Is everything ok? if ok: # Yes, run our command to find out how many control we have got. stdout = os.popen('/usr/bin/amixer controls') # See if we have all the expected controls. Are we missing some? if len(stdout.readlines()) != len(controlsAvailableList): # Yes, mark that we are not ok anymore. ok = False # Is everything still ok? if ok: # Yes, process all the found controls. for control in controls: # Does this control object has a error method? if hasattr(control, 'error'): # Yes, it has. Now run it, to see if an error in the control exist. Does it? if control.error(): # Yes, mark that we are not ok anymore. ok = False # Stop processing, since it does not make sense anymore break # Did anything go wrong and was the driver loaded? if not ok and loaded: # Yes, so mark that we still have not loaded the driver successfully. loaded = False # Stop the driver. driverStop() # A nice usage routine. def usage(): # Write the usage of this program to stdout. print 'Usage: %s {start|stop}' % (sys.argv[0]) # Quit right away. sys.exit(1) # Do we have received enough command line arguments? if len(sys.argv) >= 2: # Yes, what was the first argument received? if sys.argv[1] == 'start': # It was our command to start the driver. Start it! driverStart() elif sys.argv[1] == 'stop': # It was our command to stop the driver. Stop it! driverStop() else: # It was an unknown command. Display our usage message. usage() else: # No, display our usage message. usage() # Exit cleanly. sys.exit(0) [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2007-04-16 14:48 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-07 10:49 Trouble with sound/mips/au1x00.c AC97 driver Freddy Spierenburg
2007-03-09 7:22 ` Marco Braga
2007-03-09 10:33 ` Freddy Spierenburg
2007-03-10 13:20 ` Marco Braga
[not found] ` <45F350E9.3020208@cooper-street.com>
[not found] ` <d459bb380703120157wb3dde00p4c232e300e82fd3d@mail.gmail.com>
2007-03-12 9:59 ` Marco Braga
2007-03-12 10:39 ` Domen Puncer
2007-03-12 13:09 ` Marco Braga
2007-03-12 15:35 ` Sergei Shtylyov
2007-03-13 0:43 ` Ralf Baechle
2007-03-13 1:00 ` Andrew Dyer
2007-03-13 1:09 ` Ralf Baechle
2007-03-13 8:44 ` Marco Braga
[not found] ` <45F5DC73.9060004@cooper-street.com>
[not found] ` <d459bb380703130143w7c98e1cchdbdae6cb9a7ac7ce@mail.gmail.com>
[not found] ` <45F71FFD.202@cooper-street.com>
2007-03-13 23:12 ` Marco Braga
2007-03-15 8:04 ` Marco Braga
2007-04-16 14:47 ` Freddy Spierenburg
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.