]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.31/patches.drivers/alsa-hda-via-rec-fix
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / alsa-hda-via-rec-fix
1 From: Takashi Iwai <tiwai@suse.de>
2 Subject: ALSA: hda - Fix DMA pointer calculation on VIA chips
3 Patch-mainline: 2.6.28-rc1
4 References:
5
6 Add a workaround to calculate the DMA position on VIA chips more robustly.
7
8 Signed-off-by: Takashi Iwai <tiwai@suse.de>
9
10 ---
11 ---
12 sound/pci/hda/hda_intel.c | 95 ++++++++++++++++++++++++++++++++++++++++++++--
13 1 file changed, 91 insertions(+), 4 deletions(-)
14
15 --- a/sound/pci/hda/hda_intel.c
16 +++ b/sound/pci/hda/hda_intel.c
17 @@ -287,6 +287,11 @@ enum {
18 #define INTEL_SCH_HDA_DEVC 0x78
19 #define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11)
20
21 +/* Define IN stream 0 FIFO size offset in VIA controller */
22 +#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90
23 +/* Define VIA HD Audio Device ID*/
24 +#define VIA_HDAC_DEVICE_ID 0x3288
25 +
26
27 /*
28 */
29 @@ -318,6 +323,12 @@ struct azx_dev {
30 unsigned int running :1;
31 unsigned int irq_pending :1;
32 unsigned int irq_ignore :1;
33 + /*
34 + * For VIA:
35 + * A flag to ensure DMA position is 0
36 + * when link position is not greater than FIFO size
37 + */
38 + unsigned int insufficient :1;
39 };
40
41 /* CORB/RIRB */
42 @@ -380,6 +391,7 @@ struct azx {
43 unsigned int polling_mode :1;
44 unsigned int msi :1;
45 unsigned int irq_pending_warned :1;
46 + unsigned int via_dmapos_patch :1; /* enable DMA-position fix for VIA */
47
48 /* for debugging */
49 unsigned int last_cmd; /* last issued command (to sync) */
50 @@ -823,6 +835,11 @@ static void azx_int_clear(struct azx *ch
51 /* start a stream */
52 static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
53 {
54 + /*
55 + * Before stream start, initialize parameter
56 + */
57 + azx_dev->insufficient = 1;
58 +
59 /* enable SIE */
60 azx_writeb(chip, INTCTL,
61 azx_readb(chip, INTCTL) | (1 << azx_dev->index));
62 @@ -1156,7 +1173,8 @@ static int azx_setup_controller(struct a
63
64 /* enable the position buffer */
65 if (chip->position_fix == POS_FIX_POSBUF ||
66 - chip->position_fix == POS_FIX_AUTO) {
67 + chip->position_fix == POS_FIX_AUTO ||
68 + chip->via_dmapos_patch) {
69 if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE))
70 azx_writel(chip, DPLBASE,
71 (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE);
72 @@ -1524,13 +1542,71 @@ static int azx_pcm_trigger(struct snd_pc
73 return 0;
74 }
75
76 +/* get the current DMA position with correction on VIA chips */
77 +static unsigned int azx_via_get_position(struct azx *chip,
78 + struct azx_dev *azx_dev)
79 +{
80 + unsigned int link_pos, mini_pos, bound_pos;
81 + unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos;
82 + unsigned int fifo_size;
83 +
84 + link_pos = azx_sd_readl(azx_dev, SD_LPIB);
85 + if (azx_dev->index >= 4) {
86 + /* Playback, no problem using link position */
87 + return link_pos;
88 + }
89 +
90 + /* Capture */
91 + /* For new chipset,
92 + * use mod to get the DMA position just like old chipset
93 + */
94 + mod_dma_pos = le32_to_cpu(*azx_dev->posbuf);
95 + mod_dma_pos %= azx_dev->period_bytes;
96 +
97 + /* azx_dev->fifo_size can't get FIFO size of in stream.
98 + * Get from base address + offset.
99 + */
100 + fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET);
101 +
102 + if (azx_dev->insufficient) {
103 + /* Link position never gather than FIFO size */
104 + if (link_pos <= fifo_size)
105 + return 0;
106 +
107 + azx_dev->insufficient = 0;
108 + }
109 +
110 + if (link_pos <= fifo_size)
111 + mini_pos = azx_dev->bufsize + link_pos - fifo_size;
112 + else
113 + mini_pos = link_pos - fifo_size;
114 +
115 + /* Find nearest previous boudary */
116 + mod_mini_pos = mini_pos % azx_dev->period_bytes;
117 + mod_link_pos = link_pos % azx_dev->period_bytes;
118 + if (mod_link_pos >= fifo_size)
119 + bound_pos = link_pos - mod_link_pos;
120 + else if (mod_dma_pos >= mod_mini_pos)
121 + bound_pos = mini_pos - mod_mini_pos;
122 + else {
123 + bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes;
124 + if (bound_pos >= azx_dev->bufsize)
125 + bound_pos = 0;
126 + }
127 +
128 + /* Calculate real DMA position we want */
129 + return bound_pos + mod_dma_pos;
130 +}
131 +
132 static unsigned int azx_get_position(struct azx *chip,
133 struct azx_dev *azx_dev)
134 {
135 unsigned int pos;
136
137 - if (chip->position_fix == POS_FIX_POSBUF ||
138 - chip->position_fix == POS_FIX_AUTO) {
139 + if (chip->via_dmapos_patch)
140 + pos = azx_via_get_position(chip, azx_dev);
141 + else if (chip->position_fix == POS_FIX_POSBUF ||
142 + chip->position_fix == POS_FIX_AUTO) {
143 /* use the position buffer */
144 pos = le32_to_cpu(*azx_dev->posbuf);
145 } else {
146 @@ -1576,6 +1652,8 @@ static int azx_position_ok(struct azx *c
147 chip->position_fix = POS_FIX_POSBUF;
148 }
149
150 + if (!bdl_pos_adj[chip->dev_index])
151 + return 1; /* no delayed ack */
152 if (pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
153 return 0; /* NG - it's below the period boundary */
154 return 1; /* OK, it's fine */
155 @@ -1687,7 +1765,7 @@ static int __devinit create_codec_pcm(st
156 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
157 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
158 snd_dma_pci_data(chip->pci),
159 - 1024 * 64, 1024 * 1024);
160 + 1024 * 64, 32 * 1024 * 1024);
161 chip->pcm[cpcm->device] = pcm;
162 return 0;
163 }
164 @@ -1987,6 +2065,15 @@ static int __devinit check_position_fix(
165 {
166 const struct snd_pci_quirk *q;
167
168 + /* Check VIA HD Audio Controller exist */
169 + if (chip->pci->vendor == PCI_VENDOR_ID_VIA &&
170 + chip->pci->device == VIA_HDAC_DEVICE_ID) {
171 + chip->via_dmapos_patch = 1;
172 + /* Use link position directly, avoid any transfer problem. */
173 + return POS_FIX_LPIB;
174 + }
175 + chip->via_dmapos_patch = 0;
176 +
177 if (fix == POS_FIX_AUTO) {
178 q = snd_pci_quirk_lookup(chip->pci, position_fix_list);
179 if (q) {