Commit 2ae66c26 authored by Pierre-Louis Bossart's avatar Pierre-Louis Bossart Committed by Takashi Iwai

ALSA: hda: option to enable arbitrary buffer/period sizes

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: default avatarWu Fengguang <fengguang.wu@intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent d66fee5d
...@@ -886,6 +886,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ...@@ -886,6 +886,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
disable) disable)
power_save_controller - Reset HD-audio controller in power-saving mode power_save_controller - Reset HD-audio controller in power-saving mode
(default = on) (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. This module supports multiple cards and autoprobe.
......
...@@ -116,6 +116,11 @@ module_param(power_save_controller, bool, 0644); ...@@ -116,6 +116,11 @@ module_param(power_save_controller, bool, 0644);
MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
#endif #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_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
"{Intel, ICH6M}," "{Intel, ICH6M},"
...@@ -481,6 +486,7 @@ enum { ...@@ -481,6 +486,7 @@ enum {
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #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_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 */ /* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \ #define AZX_DCAPS_PRESET_ATI_SB \
...@@ -1599,6 +1605,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -1599,6 +1605,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_runtime *runtime = substream->runtime;
unsigned long flags; unsigned long flags;
int err; int err;
int buff_step;
mutex_lock(&chip->open_mutex); mutex_lock(&chip->open_mutex);
azx_dev = azx_assign_device(chip, substream); azx_dev = azx_assign_device(chip, substream);
...@@ -1613,10 +1620,25 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) ...@@ -1613,10 +1620,25 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
runtime->hw.rates = hinfo->rates; runtime->hw.rates = hinfo->rates;
snd_pcm_limit_hw_rates(runtime); snd_pcm_limit_hw_rates(runtime);
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 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, 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, snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
128); buff_step);
snd_hda_power_up(apcm->codec); snd_hda_power_up(apcm->codec);
err = hinfo->ops.open(hinfo, apcm->codec, substream); err = hinfo->ops.open(hinfo, apcm->codec, substream);
if (err < 0) { if (err < 0) {
...@@ -2616,6 +2638,10 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, ...@@ -2616,6 +2638,10 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci,
gcap &= ~ICH6_GCAP_64OK; 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 */ /* allow 64bit DMA address if supported by H/W */
if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
pci_set_consistent_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) ...@@ -2817,37 +2843,49 @@ static void __devexit azx_remove(struct pci_dev *pci)
static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* CPT */ /* CPT */
{ PCI_DEVICE(0x8086, 0x1c20), { 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 */ /* PBG */
{ PCI_DEVICE(0x8086, 0x1d20), { 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 */ /* Panther Point */
{ PCI_DEVICE(0x8086, 0x1e20), { 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 */ /* SCH */
{ PCI_DEVICE(0x8086, 0x811b), { 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), { 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), { 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), { 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), { 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), { 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), { 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), { 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), { 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 */ /* Generic Intel */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff, .class_mask = 0xffffff,
.driver_data = AZX_DRIVER_ICH }, .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE },
/* ATI SB 450/600/700/800/900 */ /* ATI SB 450/600/700/800/900 */
{ PCI_DEVICE(0x1002, 0x437b), { PCI_DEVICE(0x1002, 0x437b),
.driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment