diff options
author | Takashi Iwai <tiwai@suse.de> | 2005-09-05 11:11:40 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-09-12 04:41:37 -0400 |
commit | 0be3b5d3fb94c36c517655d18a936681d7108667 (patch) | |
tree | 6ce1556cfac492f4a9957c5d73d8b116d87e19cb | |
parent | a76af199dc025e8f5cf6b9542efadc3de5163a7a (diff) |
[ALSA] hda-intel - Check validity of DMA position
HDA Intel driver
Check the validity of the current DMA position when position_fix=0 (auto)
is set. If the DMA position overcomes the threshold, the driver changes
the fix behavior automatically to use POSBUF.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/hda_intel.c | 63 |
1 files changed, 41 insertions, 22 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 15107df1f490..96f9e8729192 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); | |||
62 | module_param_array(model, charp, NULL, 0444); | 62 | module_param_array(model, charp, NULL, 0444); |
63 | MODULE_PARM_DESC(model, "Use the given board model."); | 63 | MODULE_PARM_DESC(model, "Use the given board model."); |
64 | module_param_array(position_fix, int, NULL, 0444); | 64 | module_param_array(position_fix, int, NULL, 0444); |
65 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)."); | 65 | MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); |
66 | 66 | ||
67 | MODULE_LICENSE("GPL"); | 67 | MODULE_LICENSE("GPL"); |
68 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | 68 | MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," |
@@ -211,9 +211,10 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
211 | 211 | ||
212 | /* position fix mode */ | 212 | /* position fix mode */ |
213 | enum { | 213 | enum { |
214 | POS_FIX_FIFO, | 214 | POS_FIX_AUTO, |
215 | POS_FIX_NONE, | 215 | POS_FIX_NONE, |
216 | POS_FIX_POSBUF | 216 | POS_FIX_POSBUF, |
217 | POS_FIX_FIFO, | ||
217 | }; | 218 | }; |
218 | 219 | ||
219 | /* Defines for ATI HD Audio support in SB450 south bridge */ | 220 | /* Defines for ATI HD Audio support in SB450 south bridge */ |
@@ -243,6 +244,7 @@ struct snd_azx_dev { | |||
243 | unsigned int fragsize; /* size of each period in bytes */ | 244 | unsigned int fragsize; /* size of each period in bytes */ |
244 | unsigned int frags; /* number for period in the play buffer */ | 245 | unsigned int frags; /* number for period in the play buffer */ |
245 | unsigned int fifo_size; /* FIFO size */ | 246 | unsigned int fifo_size; /* FIFO size */ |
247 | unsigned int last_pos; /* last updated period position */ | ||
246 | 248 | ||
247 | void __iomem *sd_addr; /* stream descriptor pointer */ | 249 | void __iomem *sd_addr; /* stream descriptor pointer */ |
248 | 250 | ||
@@ -256,6 +258,7 @@ struct snd_azx_dev { | |||
256 | 258 | ||
257 | unsigned int opened: 1; | 259 | unsigned int opened: 1; |
258 | unsigned int running: 1; | 260 | unsigned int running: 1; |
261 | unsigned int period_updating: 1; | ||
259 | }; | 262 | }; |
260 | 263 | ||
261 | /* CORB/RIRB */ | 264 | /* CORB/RIRB */ |
@@ -724,11 +727,9 @@ static void azx_init_chip(azx_t *chip) | |||
724 | /* initialize the codec command I/O */ | 727 | /* initialize the codec command I/O */ |
725 | azx_init_cmd_io(chip); | 728 | azx_init_cmd_io(chip); |
726 | 729 | ||
727 | if (chip->position_fix == POS_FIX_POSBUF) { | 730 | /* program the position buffer */ |
728 | /* program the position buffer */ | 731 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); |
729 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | 732 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); |
730 | azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); | ||
731 | } | ||
732 | 733 | ||
733 | /* For ATI SB450 azalia HD audio, we need to enable snoop */ | 734 | /* For ATI SB450 azalia HD audio, we need to enable snoop */ |
734 | if (chip->driver_type == AZX_DRIVER_ATI) { | 735 | if (chip->driver_type == AZX_DRIVER_ATI) { |
@@ -763,9 +764,11 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs) | |||
763 | if (status & azx_dev->sd_int_sta_mask) { | 764 | if (status & azx_dev->sd_int_sta_mask) { |
764 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); | 765 | azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); |
765 | if (azx_dev->substream && azx_dev->running) { | 766 | if (azx_dev->substream && azx_dev->running) { |
767 | azx_dev->period_updating = 1; | ||
766 | spin_unlock(&chip->reg_lock); | 768 | spin_unlock(&chip->reg_lock); |
767 | snd_pcm_period_elapsed(azx_dev->substream); | 769 | snd_pcm_period_elapsed(azx_dev->substream); |
768 | spin_lock(&chip->reg_lock); | 770 | spin_lock(&chip->reg_lock); |
771 | azx_dev->period_updating = 0; | ||
769 | } | 772 | } |
770 | } | 773 | } |
771 | } | 774 | } |
@@ -866,11 +869,9 @@ static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev) | |||
866 | /* upper BDL address */ | 869 | /* upper BDL address */ |
867 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); | 870 | azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); |
868 | 871 | ||
869 | if (chip->position_fix == POS_FIX_POSBUF) { | 872 | /* enable the position buffer */ |
870 | /* enable the position buffer */ | 873 | if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) |
871 | if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) | 874 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); |
872 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); | ||
873 | } | ||
874 | 875 | ||
875 | /* set the interrupt enable bits in the descriptor control register */ | 876 | /* set the interrupt enable bits in the descriptor control register */ |
876 | azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); | 877 | azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); |
@@ -1078,6 +1079,7 @@ static int azx_pcm_prepare(snd_pcm_substream_t *substream) | |||
1078 | azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; | 1079 | azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; |
1079 | else | 1080 | else |
1080 | azx_dev->fifo_size = 0; | 1081 | azx_dev->fifo_size = 0; |
1082 | azx_dev->last_pos = 0; | ||
1081 | 1083 | ||
1082 | return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, | 1084 | return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, |
1083 | azx_dev->format_val, substream); | 1085 | azx_dev->format_val, substream); |
@@ -1133,6 +1135,26 @@ static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream) | |||
1133 | pos = azx_sd_readl(azx_dev, SD_LPIB); | 1135 | pos = azx_sd_readl(azx_dev, SD_LPIB); |
1134 | if (chip->position_fix == POS_FIX_FIFO) | 1136 | if (chip->position_fix == POS_FIX_FIFO) |
1135 | pos += azx_dev->fifo_size; | 1137 | pos += azx_dev->fifo_size; |
1138 | else if (chip->position_fix == POS_FIX_AUTO && azx_dev->period_updating) { | ||
1139 | /* check the validity of DMA position */ | ||
1140 | unsigned int diff = 0; | ||
1141 | azx_dev->last_pos += azx_dev->fragsize; | ||
1142 | if (azx_dev->last_pos > pos) | ||
1143 | diff = azx_dev->last_pos - pos; | ||
1144 | if (azx_dev->last_pos >= azx_dev->bufsize) { | ||
1145 | if (pos < azx_dev->fragsize) | ||
1146 | diff = 0; | ||
1147 | azx_dev->last_pos = 0; | ||
1148 | } | ||
1149 | if (diff > 0 && diff <= azx_dev->fifo_size) | ||
1150 | pos += azx_dev->fifo_size; | ||
1151 | else { | ||
1152 | snd_printdd(KERN_INFO "hda_intel: DMA position fix %d, switching to posbuf\n", diff); | ||
1153 | chip->position_fix = POS_FIX_POSBUF; | ||
1154 | pos = *azx_dev->posbuf; | ||
1155 | } | ||
1156 | azx_dev->period_updating = 0; | ||
1157 | } | ||
1136 | } | 1158 | } |
1137 | if (pos >= azx_dev->bufsize) | 1159 | if (pos >= azx_dev->bufsize) |
1138 | pos = 0; | 1160 | pos = 0; |
@@ -1244,8 +1266,7 @@ static int __devinit azx_init_stream(azx_t *chip) | |||
1244 | azx_dev_t *azx_dev = &chip->azx_dev[i]; | 1266 | azx_dev_t *azx_dev = &chip->azx_dev[i]; |
1245 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); | 1267 | azx_dev->bdl = (u32 *)(chip->bdl.area + off); |
1246 | azx_dev->bdl_addr = chip->bdl.addr + off; | 1268 | azx_dev->bdl_addr = chip->bdl.addr + off; |
1247 | if (chip->position_fix == POS_FIX_POSBUF) | 1269 | azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); |
1248 | azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); | ||
1249 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ | 1270 | /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ |
1250 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); | 1271 | azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); |
1251 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ | 1272 | /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ |
@@ -1437,13 +1458,11 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, | |||
1437 | snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); | 1458 | snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); |
1438 | goto errout; | 1459 | goto errout; |
1439 | } | 1460 | } |
1440 | if (chip->position_fix == POS_FIX_POSBUF) { | 1461 | /* allocate memory for the position buffer */ |
1441 | /* allocate memory for the position buffer */ | 1462 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), |
1442 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | 1463 | chip->num_streams * 8, &chip->posbuf)) < 0) { |
1443 | chip->num_streams * 8, &chip->posbuf)) < 0) { | 1464 | snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); |
1444 | snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); | 1465 | goto errout; |
1445 | goto errout; | ||
1446 | } | ||
1447 | } | 1466 | } |
1448 | /* allocate CORB/RIRB */ | 1467 | /* allocate CORB/RIRB */ |
1449 | if ((err = azx_alloc_cmd_io(chip)) < 0) | 1468 | if ((err = azx_alloc_cmd_io(chip)) < 0) |