Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=44e0b6821d7eacb4f93d2c131d436f96e500aa08
Commit:     44e0b6821d7eacb4f93d2c131d436f96e500aa08
Parent:     e5ab3a7c00e682e0e24677203856769df1b9b0cb
Author:     Adrian McMenamin <[EMAIL PROTECTED]>
AuthorDate: Thu Oct 18 10:46:59 2007 +0200
Committer:  Jaroslav Kysela <[EMAIL PROTECTED]>
CommitDate: Tue Oct 23 08:04:33 2007 +0200

    [ALSA] protect Dreamcast PCM driver (AICA) from G2 bus effects
    
    The G2 bus on the SEGA Dreamcast connects both the maple peripheral
    bus and the AICA sound memory. DMA requests on one can cause the other
    to timeout on memory operations.
    This patch prevents maple interrupts from causing hiccoughs in the
    AICA sound (maple bus code will land in 2.6.24).
    There are other cleanups for this (AICA) code - but this is in effect
    a regression fix rather than a cleanup.
    
    Signed-off-by: Adrian McMenamin <[EMAIL PROTECTED]>
    Signed-off-by: Takashi Iwai <[EMAIL PROTECTED]>
    Signed-off-by: Jaroslav Kysela <[EMAIL PROTECTED]>
---
 sound/sh/aica.c |   31 +++++++++++++++++++++++++++++--
 1 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 131ec48..88dc840 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -106,11 +106,14 @@ static void spu_write_wait(void)
 static void spu_memset(u32 toi, u32 what, int length)
 {
        int i;
+       unsigned long flags;
        snd_assert(length % 4 == 0, return);
        for (i = 0; i < length; i++) {
                if (!(i % 8))
                        spu_write_wait();
+               local_irq_save(flags);
                writel(what, toi + SPU_MEMORY_BASE);
+               local_irq_restore(flags);
                toi++;
        }
 }
@@ -118,6 +121,7 @@ static void spu_memset(u32 toi, u32 what, int length)
 /* spu_memload - write to SPU address space */
 static void spu_memload(u32 toi, void *from, int length)
 {
+       unsigned long flags;
        u32 *froml = from;
        u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
        int i;
@@ -128,7 +132,9 @@ static void spu_memload(u32 toi, void *from, int length)
                if (!(i % 8))
                        spu_write_wait();
                val = *froml;
+               local_irq_save(flags);
                writel(val, to);
+               local_irq_restore(flags);
                froml++;
                to++;
        }
@@ -138,28 +144,36 @@ static void spu_memload(u32 toi, void *from, int length)
 static void spu_disable(void)
 {
        int i;
+       unsigned long flags;
        u32 regval;
        spu_write_wait();
        regval = readl(ARM_RESET_REGISTER);
        regval |= 1;
        spu_write_wait();
+       local_irq_save(flags);
        writel(regval, ARM_RESET_REGISTER);
+       local_irq_restore(flags);
        for (i = 0; i < 64; i++) {
                spu_write_wait();
                regval = readl(SPU_REGISTER_BASE + (i * 0x80));
                regval = (regval & ~0x4000) | 0x8000;
                spu_write_wait();
+               local_irq_save(flags);
                writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+               local_irq_restore(flags);
        }
 }
 
 /* spu_enable - set spu registers to enable sound output */
 static void spu_enable(void)
 {
+       unsigned long flags;
        u32 regval = readl(ARM_RESET_REGISTER);
        regval &= ~1;
        spu_write_wait();
+       local_irq_save(flags);
        writel(regval, ARM_RESET_REGISTER);
+       local_irq_restore(flags);
 }
 
 /* 
@@ -168,25 +182,34 @@ static void spu_enable(void)
 */
 static void spu_reset(void)
 {
+       unsigned long flags;
        spu_disable();
        spu_memset(0, 0, 0x200000 / 4);
        /* Put ARM7 in endless loop */
+       local_irq_save(flags);
        ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+       local_irq_restore(flags);
        spu_enable();
 }
 
 /* aica_chn_start - write to spu to start playback */
 static void aica_chn_start(void)
 {
+       unsigned long flags;
        spu_write_wait();
+       local_irq_save(flags);
        writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
+       local_irq_restore(flags);
 }
 
 /* aica_chn_halt - write to spu to halt playback */
 static void aica_chn_halt(void)
 {
+       unsigned long flags;
        spu_write_wait();
+       local_irq_save(flags);
        writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
+       local_irq_restore(flags);
 }
 
 /* ALSA code below */
@@ -213,12 +236,13 @@ static int aica_dma_transfer(int channels, int 
buffer_size,
        int q, err, period_offset;
        struct snd_card_aica *dreamcastcard;
        struct snd_pcm_runtime *runtime;
-       err = 0;
+       unsigned long flags;
        dreamcastcard = substream->pcm->private_data;
        period_offset = dreamcastcard->clicks;
        period_offset %= (AICA_PERIOD_NUMBER / channels);
        runtime = substream->runtime;
        for (q = 0; q < channels; q++) {
+               local_irq_save(flags);
                err = dma_xfer(AICA_DMA_CHANNEL,
                               (unsigned long) (runtime->dma_area +
                                                (AICA_BUFFER_SIZE * q) /
@@ -228,9 +252,12 @@ static int aica_dma_transfer(int channels, int buffer_size,
                               AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
                               AICA_PERIOD_SIZE * period_offset,
                               buffer_size / channels, AICA_DMA_MODE);
-               if (unlikely(err < 0))
+               if (unlikely(err < 0)) {
+                       local_irq_restore(flags);
                        break;
+               }
                dma_wait_for_completion(AICA_DMA_CHANNEL);
+               local_irq_restore(flags);
        }
        return err;
 }
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to