aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/hda_intel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/hda_intel.c')
-rw-r--r--sound/pci/hda/hda_intel.c117
1 files changed, 85 insertions, 32 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index dc68709e7569..1ec3fd4c8940 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -58,6 +58,7 @@ static int position_fix[SNDRV_CARDS];
58static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; 58static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
59static int single_cmd; 59static int single_cmd;
60static int enable_msi; 60static int enable_msi;
61static int bdl_pos_adj = 1;
61 62
62module_param_array(index, int, NULL, 0444); 63module_param_array(index, int, NULL, 0444);
63MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); 64MODULE_PARM_DESC(index, "Index value for Intel HD audio interface.");
@@ -77,6 +78,8 @@ MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
77 "(for debugging only)."); 78 "(for debugging only).");
78module_param(enable_msi, int, 0444); 79module_param(enable_msi, int, 0444);
79MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); 80MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)");
81module_param(bdl_pos_adj, int, 0644);
82MODULE_PARM_DESC(bdl_pos_adj, "BDL position adjustment offset");
80 83
81#ifdef CONFIG_SND_HDA_POWER_SAVE 84#ifdef CONFIG_SND_HDA_POWER_SAVE
82/* power_save option is defined in hda_codec.c */ 85/* power_save option is defined in hda_codec.c */
@@ -309,7 +312,8 @@ struct azx_dev {
309 312
310 unsigned int opened :1; 313 unsigned int opened :1;
311 unsigned int running :1; 314 unsigned int running :1;
312 unsigned int irq_pending: 1; 315 unsigned int irq_pending :1;
316 unsigned int irq_ignore :1;
313}; 317};
314 318
315/* CORB/RIRB */ 319/* CORB/RIRB */
@@ -943,6 +947,11 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
943 azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); 947 azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
944 if (!azx_dev->substream || !azx_dev->running) 948 if (!azx_dev->substream || !azx_dev->running)
945 continue; 949 continue;
950 /* ignore the first dummy IRQ (due to pos_adj) */
951 if (azx_dev->irq_ignore) {
952 azx_dev->irq_ignore = 0;
953 continue;
954 }
946 /* check whether this IRQ is really acceptable */ 955 /* check whether this IRQ is really acceptable */
947 if (azx_position_ok(chip, azx_dev)) { 956 if (azx_position_ok(chip, azx_dev)) {
948 azx_dev->irq_pending = 0; 957 azx_dev->irq_pending = 0;
@@ -977,14 +986,53 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
977 986
978 987
979/* 988/*
989 * set up a BDL entry
990 */
991static int setup_bdle(struct snd_pcm_substream *substream,
992 struct azx_dev *azx_dev, u32 **bdlp,
993 int ofs, int size, int with_ioc)
994{
995 struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
996 u32 *bdl = *bdlp;
997
998 while (size > 0) {
999 dma_addr_t addr;
1000 int chunk;
1001
1002 if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES)
1003 return -EINVAL;
1004
1005 addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs);
1006 /* program the address field of the BDL entry */
1007 bdl[0] = cpu_to_le32((u32)addr);
1008 bdl[1] = cpu_to_le32(upper_32bit(addr));
1009 /* program the size field of the BDL entry */
1010 chunk = PAGE_SIZE - (ofs % PAGE_SIZE);
1011 if (size < chunk)
1012 chunk = size;
1013 bdl[2] = cpu_to_le32(chunk);
1014 /* program the IOC to enable interrupt
1015 * only when the whole fragment is processed
1016 */
1017 size -= chunk;
1018 bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01);
1019 bdl += 4;
1020 azx_dev->frags++;
1021 ofs += chunk;
1022 }
1023 *bdlp = bdl;
1024 return ofs;
1025}
1026
1027/*
980 * set up BDL entries 1028 * set up BDL entries
981 */ 1029 */
982static int azx_setup_periods(struct snd_pcm_substream *substream, 1030static int azx_setup_periods(struct snd_pcm_substream *substream,
983 struct azx_dev *azx_dev) 1031 struct azx_dev *azx_dev)
984{ 1032{
985 struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
986 u32 *bdl; 1033 u32 *bdl;
987 int i, ofs, periods, period_bytes; 1034 int i, ofs, periods, period_bytes;
1035 int pos_adj = 0;
988 1036
989 /* reset BDL address */ 1037 /* reset BDL address */
990 azx_sd_writel(azx_dev, SD_BDLPL, 0); 1038 azx_sd_writel(azx_dev, SD_BDLPL, 0);
@@ -998,39 +1046,44 @@ static int azx_setup_periods(struct snd_pcm_substream *substream,
998 bdl = (u32 *)azx_dev->bdl.area; 1046 bdl = (u32 *)azx_dev->bdl.area;
999 ofs = 0; 1047 ofs = 0;
1000 azx_dev->frags = 0; 1048 azx_dev->frags = 0;
1001 for (i = 0; i < periods; i++) { 1049 azx_dev->irq_ignore = 0;
1002 int size, rest; 1050 if (bdl_pos_adj > 0) {
1003 if (i >= AZX_MAX_BDL_ENTRIES) { 1051 struct snd_pcm_runtime *runtime = substream->runtime;
1004 snd_printk(KERN_ERR "Too many BDL entries: " 1052 pos_adj = (bdl_pos_adj * runtime->rate + 47999) / 48000;
1005 "buffer=%d, period=%d\n", 1053 if (!pos_adj)
1006 azx_dev->bufsize, period_bytes); 1054 pos_adj = 1;
1007 /* reset */ 1055 pos_adj = frames_to_bytes(runtime, pos_adj);
1008 azx_sd_writel(azx_dev, SD_BDLPL, 0); 1056 if (pos_adj >= period_bytes) {
1009 azx_sd_writel(azx_dev, SD_BDLPU, 0); 1057 snd_printk(KERN_WARNING "Too big adjustment %d\n",
1010 return -EINVAL; 1058 bdl_pos_adj);
1059 pos_adj = 0;
1060 } else {
1061 ofs = setup_bdle(substream, azx_dev,
1062 &bdl, ofs, pos_adj, 1);
1063 if (ofs < 0)
1064 goto error;
1065 azx_dev->irq_ignore = 1;
1011 } 1066 }
1012 rest = period_bytes; 1067 }
1013 do { 1068 for (i = 0; i < periods; i++) {
1014 dma_addr_t addr = snd_pcm_sgbuf_get_addr(sgbuf, ofs); 1069 if (i == periods - 1 && pos_adj)
1015 /* program the address field of the BDL entry */ 1070 ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
1016 bdl[0] = cpu_to_le32((u32)addr); 1071 period_bytes - pos_adj, 0);
1017 bdl[1] = cpu_to_le32(upper_32bit(addr)); 1072 else
1018 /* program the size field of the BDL entry */ 1073 ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
1019 size = PAGE_SIZE - (ofs % PAGE_SIZE); 1074 period_bytes, 1);
1020 if (rest < size) 1075 if (ofs < 0)
1021 size = rest; 1076 goto error;
1022 bdl[2] = cpu_to_le32(size);
1023 /* program the IOC to enable interrupt
1024 * only when the whole fragment is processed
1025 */
1026 rest -= size;
1027 bdl[3] = rest ? 0 : cpu_to_le32(0x01);
1028 bdl += 4;
1029 azx_dev->frags++;
1030 ofs += size;
1031 } while (rest > 0);
1032 } 1077 }
1033 return 0; 1078 return 0;
1079
1080 error:
1081 snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
1082 azx_dev->bufsize, period_bytes);
1083 /* reset */
1084 azx_sd_writel(azx_dev, SD_BDLPL, 0);
1085 azx_sd_writel(azx_dev, SD_BDLPU, 0);
1086 return -EINVAL;
1034} 1087}
1035 1088
1036/* 1089/*