[alsa-devel] [PATCH] ALSA: hda: option to enable arbitrary buffer/period sizes

Pierre-Louis Bossart pierre-louis.bossart at linux.intel.com
Thu Aug 4 17:12:56 CEST 2011


Add new parameter to disable rounding of buffer/period sizes to
multiples of 128 bytes. This is more efficient in terms of memory
access but isn't required by the HDA spec and prevents users from
specifying exact period/buffer sizes. For example for 44.1kHz, a
period size set to 20ms will be rounded to 19.59ms.

Tested and enabled on Intel HDA controllers. Option is disabled by
default for other controllers.

Tested-by: Wu Fengguang <fengguang.wu at intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
---
 Documentation/sound/alsa/ALSA-Configuration.txt |    5 ++
 sound/pci/hda/hda_intel.c                       |   68 ++++++++++++++++++-----
 2 files changed, 58 insertions(+), 15 deletions(-)

diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 8975701..27126c4 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -886,6 +886,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
 		disable)
     power_save_controller - Reset HD-audio controller in power-saving mode
 		(default = on)
+    align_buffer_size - Force rounding of buffer/period sizes to multiples
+    		      of 128 bytes. This is more efficient in terms of memory
+		      access but isn't required by the HDA spec and prevents
+		      users from specifying exact period/buffer sizes.
+		      (default = on)
 
     This module supports multiple cards and autoprobe.
     
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index be69822..2a8bed9 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -116,6 +116,11 @@ module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #endif
 
+static int align_buffer_size = 1;
+module_param(align_buffer_size, bool, 0644);
+MODULE_PARM_DESC(align_buffer_size,
+		"Force buffer and period sizes to be multiple of 128 bytes.");
+
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
 			 "{Intel, ICH6M},"
@@ -481,6 +486,7 @@ enum {
 #define AZX_DCAPS_NO_64BIT	(1 << 18)	/* No 64bit address */
 #define AZX_DCAPS_SYNC_WRITE	(1 << 19)	/* sync each cmd write */
 #define AZX_DCAPS_OLD_SSYNC	(1 << 20)	/* Old SSYNC reg for ICH */
+#define AZX_DCAPS_BUFSIZE	(1 << 21)	/* no buffer size alignment */
 
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
@@ -1599,6 +1605,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	unsigned long flags;
 	int err;
+	int buff_step;
 
 	mutex_lock(&chip->open_mutex);
 	azx_dev = azx_assign_device(chip, substream);
@@ -1613,10 +1620,25 @@ 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)
+		/* 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
+		   prevents users from specifying exact period/buffer
+		   sizes. For example for 44.1kHz, a period size set
+		   to 20ms will be rounded to 19.59ms. */
+		buff_step = 128;
+	else
+		/* Don't enforce steps on buffer sizes, still need to
+		   be multiple of 4 bytes (HDA spec). Tested on Intel
+		   HDA controllers, may not work on all devices where
+		   option needs to be disabled */
+		buff_step = 4;
+
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
-				   128);
+				   buff_step);
 	snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
-				   128);
+				   buff_step);
 	snd_hda_power_up(apcm->codec);
 	err = hinfo->ops.open(hinfo, apcm->codec, substream);
 	if (err < 0) {
@@ -2616,6 +2638,10 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
 		gcap &= ~ICH6_GCAP_64OK;
 	}
 
+	/* disable buffer size rounding to 128-byte multiples if supported */
+	if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
+		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)))
 		pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
@@ -2817,37 +2843,49 @@ static void __devexit azx_remove(struct pci_dev *pci)
 static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
 	/* CPT */
 	{ PCI_DEVICE(0x8086, 0x1c20),
-	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+	  AZX_DCAPS_BUFSIZE },
 	/* PBG */
 	{ PCI_DEVICE(0x8086, 0x1d20),
-	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
+	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+	  AZX_DCAPS_BUFSIZE},
 	/* Panther Point */
 	{ PCI_DEVICE(0x8086, 0x1e20),
-	  .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP },
+	  .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 },
+	  .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
+	  AZX_DCAPS_BUFSIZE},
 	{ PCI_DEVICE(0x8086, 0x2668),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH6 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ICH6 */
 	{ PCI_DEVICE(0x8086, 0x27d8),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH7 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ICH7 */
 	{ PCI_DEVICE(0x8086, 0x269a),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ESB2 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ESB2 */
 	{ PCI_DEVICE(0x8086, 0x284b),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH8 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ICH8 */
 	{ PCI_DEVICE(0x8086, 0x293e),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH9 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ICH9 */
 	{ PCI_DEVICE(0x8086, 0x293f),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH9 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ICH9 */
 	{ PCI_DEVICE(0x8086, 0x3a3e),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH10 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ICH10 */
 	{ PCI_DEVICE(0x8086, 0x3a6e),
-	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC },  /* ICH10 */
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
+	  AZX_DCAPS_BUFSIZE },  /* ICH10 */
 	/* Generic Intel */
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
 	  .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
 	  .class_mask = 0xffffff,
-	  .driver_data = AZX_DRIVER_ICH },
+	  .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE },
 	/* ATI SB 450/600/700/800/900 */
 	{ PCI_DEVICE(0x1002, 0x437b),
 	  .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
-- 
1.7.6



More information about the Alsa-devel mailing list