ALSA: hda - Fix non-snoop page handling
[pandora-kernel.git] / sound / pci / hda / hda_intel.c
index 096507d..a166a85 100644 (file)
@@ -148,6 +148,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, PCH},"
                         "{Intel, CPT},"
                         "{Intel, PPT},"
+                        "{Intel, LPT},"
                         "{Intel, PBG},"
                         "{Intel, SCH},"
                         "{ATI, SB450},"
@@ -461,6 +462,7 @@ struct azx {
        unsigned int irq_pending_warned :1;
        unsigned int probing :1; /* codec probing phase */
        unsigned int snoop:1;
+       unsigned int align_buffer_size:1;
 
        /* for debugging */
        unsigned int last_cmd[AZX_MAX_CODECS];
@@ -567,29 +569,43 @@ static char *driver_short_names[] __devinitdata = {
 #define get_azx_dev(substream) (substream->runtime->private_data)
 
 #ifdef CONFIG_X86
-static void __mark_pages_wc(struct azx *chip, void *addr, size_t size, bool on)
+static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on)
 {
+       int pages;
+
        if (azx_snoop(chip))
                return;
-       if (addr && size) {
-               int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (!dmab || !dmab->area || !dmab->bytes)
+               return;
+
+#ifdef CONFIG_SND_DMA_SGBUF
+       if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) {
+               struct snd_sg_buf *sgbuf = dmab->private_data;
                if (on)
-                       set_memory_wc((unsigned long)addr, pages);
+                       set_pages_array_wc(sgbuf->page_table, sgbuf->pages);
                else
-                       set_memory_wb((unsigned long)addr, pages);
+                       set_pages_array_wb(sgbuf->page_table, sgbuf->pages);
+               return;
        }
+#endif
+
+       pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (on)
+               set_memory_wc((unsigned long)dmab->area, pages);
+       else
+               set_memory_wb((unsigned long)dmab->area, pages);
 }
 
 static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
                                 bool on)
 {
-       __mark_pages_wc(chip, buf->area, buf->bytes, on);
+       __mark_pages_wc(chip, buf, on);
 }
 static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-                                  struct snd_pcm_runtime *runtime, bool on)
+                                  struct snd_pcm_substream *substream, bool on)
 {
        if (azx_dev->wc_marked != on) {
-               __mark_pages_wc(chip, runtime->dma_area, runtime->dma_bytes, on);
+               __mark_pages_wc(chip, substream->runtime->dma_buffer_p, on);
                azx_dev->wc_marked = on;
        }
 }
@@ -600,7 +616,7 @@ static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf,
 {
 }
 static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev,
-                                  struct snd_pcm_runtime *runtime, bool on)
+                                  struct snd_pcm_substream *substream, bool on)
 {
 }
 #endif
@@ -768,11 +784,13 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
 {
        struct azx *chip = bus->private_data;
        unsigned long timeout;
+       unsigned long loopcounter;
        int do_poll = 0;
 
  again:
        timeout = jiffies + msecs_to_jiffies(1000);
-       for (;;) {
+
+       for (loopcounter = 0;; loopcounter++) {
                if (chip->polling_mode || do_poll) {
                        spin_lock_irq(&chip->reg_lock);
                        azx_update_rirb(chip);
@@ -788,7 +806,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus,
                }
                if (time_after(jiffies, timeout))
                        break;
-               if (bus->needs_damn_long_delay)
+               if (bus->needs_damn_long_delay || loopcounter > 3000)
                        msleep(2); /* temporary workaround */
                else {
                        udelay(10);
@@ -1697,7 +1715,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
        runtime->hw.rates = hinfo->rates;
        snd_pcm_limit_hw_rates(runtime);
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-       if (align_buffer_size)
+       if (chip->align_buffer_size)
                /* constrain buffer sizes to be multiple of 128
                   bytes. This is more efficient in terms of memory
                   access but isn't required by the HDA spec and
@@ -1772,11 +1790,10 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx *chip = apcm->chip;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        struct azx_dev *azx_dev = get_azx_dev(substream);
        int ret;
 
-       mark_runtime_wc(chip, azx_dev, runtime, false);
+       mark_runtime_wc(chip, azx_dev, substream, false);
        azx_dev->bufsize = 0;
        azx_dev->period_bytes = 0;
        azx_dev->format_val = 0;
@@ -1784,7 +1801,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
                                        params_buffer_bytes(hw_params));
        if (ret < 0)
                return ret;
-       mark_runtime_wc(chip, azx_dev, runtime, true);
+       mark_runtime_wc(chip, azx_dev, substream, true);
        return ret;
 }
 
@@ -1793,7 +1810,6 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
        struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
        struct azx_dev *azx_dev = get_azx_dev(substream);
        struct azx *chip = apcm->chip;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
 
        /* reset BDL address */
@@ -1806,7 +1822,7 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
 
        snd_hda_codec_cleanup(apcm->codec, hinfo, substream);
 
-       mark_runtime_wc(chip, azx_dev, runtime, false);
+       mark_runtime_wc(chip, azx_dev, substream, false);
        return snd_pcm_lib_free_pages(substream);
 }
 
@@ -2507,8 +2523,9 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS 1101HA", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
-       SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
+       SND_PCI_QUIRK(0x10de, 0xcb89, "Macbook Pro 7,1", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1297, 0x3166, "Shuttle", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB),
        SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
@@ -2752,8 +2769,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
        }
 
        /* disable buffer size rounding to 128-byte multiples if supported */
+       chip->align_buffer_size = align_buffer_size;
        if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
-               align_buffer_size = 0;
+               chip->align_buffer_size = 0;
 
        /* allow 64bit DMA address if supported by H/W */
        if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
@@ -2968,10 +2986,15 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(0x8086, 0x1e20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
          AZX_DCAPS_BUFSIZE},
+       /* Lynx Point */
+       { PCI_DEVICE(0x8086, 0x8c20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE},
        /* SCH */
        { PCI_DEVICE(0x8086, 0x811b),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
-         AZX_DCAPS_BUFSIZE},
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */
+       /* ICH */
        { PCI_DEVICE(0x8086, 0x2668),
          .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
          AZX_DCAPS_BUFSIZE },  /* ICH6 */