[alsa-devel] [PATCH v2 0/6] dma: Indicate residue granularity in dma_slave_caps
Here is an updated version of the DMA residue granularity patchset. As discuessed last time it would be best if this could go through ASoC tree. It needs some feedback from the DMA folks first though.
New in v2: * Dropped byte level granularity as discussed during v1 review * Added support for auto-detecting the NO_RESIDUE flag on the compat path in the generic ASoC dmaengine PCM driver * Updated a few ASoC drivers to take advantage of the new API
Updated original cover text from v1 below:
This patch series introduces a new field to the dma_slave_caps struct which exposes the granularity with which the reported residue is updated, updates the pl330 DMA driver to set this field and lets the generic dmaengine PCM audio driver check that field.
The reason for introducing the field is that for audio we need to know the granularity with which the reported residue is updated. The uncertainty of the ALSA period pointer depends on the granularity of the reported residue. E.g. if residue is only updated once every period this means that the position in the buffer from/to which the hardware is currently reading/writing could be anywhere between the reported PCM pointer and the reported PCM pointer plus one period size (plus some extra margin for interrupt latency, etc). Certain algorithms (e.g. pulseaudio's timer based scheduling) only work correctly if the uncertainty of the PCM pointer is low enough. Exposing this information from the DMA driver makes it possible for applications to switch to alternative modes of operation which also work with a high granularity.
The patch series introduces four levels of granularity, which I think will cover most DMA cores. I'd like some feedback though if anybody can think of a DMA controller for which none of the levels would be correct. The four levels are: * DESCRIPTOR: The DMA channel is only able to tell whether a descriptor has been completed or not, which means residue reporting is not supported by this channel. The residue field of the dma_tx_state field will always be 0. * SEGMENT: The DMA channel updates the residue field after each successfully completed segment of the transfer (For cyclic transfers this is after each period). This is typically implemented by having the hardware generate an interrupt after each transferred segment and then the driver updates the outstanding residue by the size of the segment. Another possibility is if the hardware supports SG and the segment descriptor has a field which gets set by the hardware after the segment has been completed. The driver then counts the number of segments which do not have the flag set to compute the residue. * BURST: The DMA channel updates the residue field after each transferred burst. This is typically only supported if the hardware has a progress register of some sort (E.g. a register with the current read/write address or a register with the amount of bursts/beats/bytes that have been transferred or still need to be transferred).
- Lars
Lars-Peter Clausen (6): dma: Indicate residue granularity in dma_slave_caps dma: pl330: Set residue_granularity ASoC: generic-dmaengine-pcm: Check NO_RESIDUE flag at runtime ASoC: generic-dmaengine-pcm: Check DMA residue granularity ASoC: axi-{spdif,i2s}: Drop NO_RESIDUE flag ASoC: samsung: Remove NO_RESIDUE flag
drivers/dma/pl330.c | 1 + include/linux/dmaengine.h | 15 ++++++++ sound/soc/adi/axi-i2s.c | 3 +- sound/soc/adi/axi-spdif.c | 3 +- sound/soc/samsung/dmaengine.c | 1 - sound/soc/soc-generic-dmaengine-pcm.c | 66 ++++++++++++++++++++++------------- 6 files changed, 60 insertions(+), 29 deletions(-)
This patch adds a new field to the dma_slave_caps struct which indicates the granularity with which the driver is able to update the residue field of the dma_tx_state struct. Making this information available to dmaengine users allows them to make better decisions on how to operate. E.g. for audio certain features like wakeup less operation or timer based scheduling only make sense and work correctly if the reported residue is fine-grained enough.
Right now four different levels of granularity are supported: * DESCRIPTOR: The DMA channel is only able to tell whether a descriptor has been completed or not, which means residue reporting is not supported by this channel. The residue field of the dma_tx_state field will always be 0. * SEGMENT: The DMA channel updates the residue field after each successfully completed segment of the transfer (For cyclic transfers this is after each period). This is typically implemented by having the hardware generate an interrupt after each transferred segment and then the drivers updates the outstanding residue by the size of the segment. Another possibility is if the hardware supports SG and the segment descriptor has a field which gets set after the segment has been completed. The driver then counts the number of segments without the flag set to compute the residue. * BURST: The DMA channel updates the residue field after each transferred burst. This is typically only supported if the hardware has a progress register of some sort (E.g. a register with the current read/write address or a register with the amount of bursts/beats/bytes that have been transferred or still need to be transferred).
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- Changes since v1: * Drop BYTE granularity level as there has been consent that it is not really useful. --- include/linux/dmaengine.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index ed92b30..74d5cb2 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -364,6 +364,19 @@ struct dma_slave_config { unsigned int slave_id; };
+/** + * enum dma_residue_granularity - Granularity of the reported transfer residue + * @DMA_RESIDUE_GRANULATRITY_DESCRIPTOR: Residue reporting is not supported. + * @DMA_RESIDUE_GRANULATRITY_SEGMENT: Residue is updated with each completed + * segment in the descriptor. + * @DMA_RESIDUE_GRANULATRITY_BURST: Residue is updated with each transfered burst + */ +enum dma_residue_granularity { + DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0, + DMA_RESIDUE_GRANULARITY_SEGMENT = 1, + DMA_RESIDUE_GRANULARITY_BURST = 2, +}; + /* struct dma_slave_caps - expose capabilities of a slave channel only * * @src_addr_widths: bit mask of src addr widths the channel supports @@ -374,6 +387,7 @@ struct dma_slave_config { * should be checked by controller as well * @cmd_pause: true, if pause and thereby resume is supported * @cmd_terminate: true, if terminate cmd is supported + * @residue_granularity: granularity of the reported transfer residue */ struct dma_slave_caps { u32 src_addr_widths; @@ -381,6 +395,7 @@ struct dma_slave_caps { u32 directions; bool cmd_pause; bool cmd_terminate; + enum dma_residue_granularity residue_granularity; };
static inline const char *dma_chan_name(struct dma_chan *chan)
On Mon, Jan 06, 2014 at 11:45:57AM +0100, Lars-Peter Clausen wrote:
This patch adds a new field to the dma_slave_caps struct which indicates the granularity with which the driver is able to update the residue field of the dma_tx_state struct. Making this information available to dmaengine users allows them to make better decisions on how to operate. E.g. for audio certain features like wakeup less operation or timer based scheduling only make sense and work correctly if the reported residue is fine-grained enough.
Right now four different levels of granularity are supported:
- DESCRIPTOR: The DMA channel is only able to tell whether a descriptor has been completed or not, which means residue reporting is not supported by this channel. The residue field of the dma_tx_state field will always be 0.
- SEGMENT: The DMA channel updates the residue field after each successfully completed segment of the transfer (For cyclic transfers this is after each period). This is typically implemented by having the hardware generate an interrupt after each transferred segment and then the drivers updates the outstanding residue by the size of the segment. Another possibility is if the hardware supports SG and the segment descriptor has a field which gets set after the segment has been completed. The driver then counts the number of segments without the flag set to compute the residue.
- BURST: The DMA channel updates the residue field after each transferred burst. This is typically only supported if the hardware has a progress register of some sort (E.g. a register with the current read/write address or a register with the amount of bursts/beats/bytes that have been transferred or still need to be transferred).
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
Changes since v1:
- Drop BYTE granularity level as there has been consent that it is not really useful.
include/linux/dmaengine.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index ed92b30..74d5cb2 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -364,6 +364,19 @@ struct dma_slave_config { unsigned int slave_id; };
+/**
- enum dma_residue_granularity - Granularity of the reported transfer residue
- @DMA_RESIDUE_GRANULATRITY_DESCRIPTOR: Residue reporting is not supported.
- @DMA_RESIDUE_GRANULATRITY_SEGMENT: Residue is updated with each completed
- segment in the descriptor.
- @DMA_RESIDUE_GRANULATRITY_BURST: Residue is updated with each transfered burst
- */
+enum dma_residue_granularity {
- DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0,
- DMA_RESIDUE_GRANULARITY_SEGMENT = 1,
- DMA_RESIDUE_GRANULARITY_BURST = 2,
This is too longish macro :) Cna we just have DMA_RESIDUE_XXXX. Do we really need granularity?
Also segment is not too obvious, block is genrally used in DMA controllers for this, though not too relgious about it!
Can you also add bit more detail in enum descriptions. Move a bit from patch description above :)
+};
/* struct dma_slave_caps - expose capabilities of a slave channel only
- @src_addr_widths: bit mask of src addr widths the channel supports
@@ -374,6 +387,7 @@ struct dma_slave_config {
- should be checked by controller as well
- @cmd_pause: true, if pause and thereby resume is supported
- @cmd_terminate: true, if terminate cmd is supported
*/
- @residue_granularity: granularity of the reported transfer residue
struct dma_slave_caps { u32 src_addr_widths; @@ -381,6 +395,7 @@ struct dma_slave_caps { u32 directions; bool cmd_pause; bool cmd_terminate;
- enum dma_residue_granularity residue_granularity;
enum dma_residue granularity; would be fine too...
-- ~Vinod
On 01/09/2014 04:08 PM, Vinod Koul wrote:
On Mon, Jan 06, 2014 at 11:45:57AM +0100, Lars-Peter Clausen wrote:
This patch adds a new field to the dma_slave_caps struct which indicates the granularity with which the driver is able to update the residue field of the dma_tx_state struct. Making this information available to dmaengine users allows them to make better decisions on how to operate. E.g. for audio certain features like wakeup less operation or timer based scheduling only make sense and work correctly if the reported residue is fine-grained enough.
Right now four different levels of granularity are supported:
- DESCRIPTOR: The DMA channel is only able to tell whether a descriptor has been completed or not, which means residue reporting is not supported by this channel. The residue field of the dma_tx_state field will always be 0.
- SEGMENT: The DMA channel updates the residue field after each successfully completed segment of the transfer (For cyclic transfers this is after each period). This is typically implemented by having the hardware generate an interrupt after each transferred segment and then the drivers updates the outstanding residue by the size of the segment. Another possibility is if the hardware supports SG and the segment descriptor has a field which gets set after the segment has been completed. The driver then counts the number of segments without the flag set to compute the residue.
- BURST: The DMA channel updates the residue field after each transferred burst. This is typically only supported if the hardware has a progress register of some sort (E.g. a register with the current read/write address or a register with the amount of bursts/beats/bytes that have been transferred or still need to be transferred).
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
Changes since v1:
- Drop BYTE granularity level as there has been consent that it is not really useful.
include/linux/dmaengine.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index ed92b30..74d5cb2 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -364,6 +364,19 @@ struct dma_slave_config { unsigned int slave_id; };
+/**
- enum dma_residue_granularity - Granularity of the reported transfer residue
- @DMA_RESIDUE_GRANULATRITY_DESCRIPTOR: Residue reporting is not supported.
- @DMA_RESIDUE_GRANULATRITY_SEGMENT: Residue is updated with each completed
- segment in the descriptor.
- @DMA_RESIDUE_GRANULATRITY_BURST: Residue is updated with each transfered burst
- */
+enum dma_residue_granularity {
- DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0,
- DMA_RESIDUE_GRANULARITY_SEGMENT = 1,
- DMA_RESIDUE_GRANULARITY_BURST = 2,
This is too longish macro :) Cna we just have DMA_RESIDUE_XXXX. Do we really need granularity?
How about DMA_RSD_GRNLRTY? ;)
I'd prefer to keep the name as it is. In my opinion the intuitive meaning changes completely if you leave out the "granularity".
Also segment is not too obvious, block is genrally used in DMA controllers for this, though not too relgious about it!
I'd like to stick with the kernel terminology.
Can you also add bit more detail in enum descriptions. Move a bit from patch description above :)
Ok.
+};
/* struct dma_slave_caps - expose capabilities of a slave channel only
- @src_addr_widths: bit mask of src addr widths the channel supports
@@ -374,6 +387,7 @@ struct dma_slave_config {
- should be checked by controller as well
- @cmd_pause: true, if pause and thereby resume is supported
- @cmd_terminate: true, if terminate cmd is supported
*/
- @residue_granularity: granularity of the reported transfer residue
struct dma_slave_caps { u32 src_addr_widths; @@ -381,6 +395,7 @@ struct dma_slave_caps { u32 directions; bool cmd_pause; bool cmd_terminate;
- enum dma_residue_granularity residue_granularity;
enum dma_residue granularity; would be fine too...
-- ~Vinod -- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
The pl330 driver currently does not support residue reporting, so set the residue granularity to DMA_RESIDUE_GRANULARITY_DESCRIPTOR.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- No changes since v1 --- drivers/dma/pl330.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 536632f..c90edec 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2884,6 +2884,7 @@ static int pl330_dma_device_slave_caps(struct dma_chan *dchan, caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); caps->cmd_pause = false; caps->cmd_terminate = true; + caps->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
return 0; }
Currently we have two different snd_soc_platform_driver structs in the generic dmaengine PCM driver. One for dmaengine drivers that support residue reporting and one for those which do not. When registering the PCM component we check whether the NO_RESIDUE flag is set or not and use the corresponding snd_soc_platform_driver. This patch modifies the driver to only have one snd_soc_platform_driver struct where the pointer() callback checks the NO_RESIDUE flag at runtime. This allows us to set the NO_RESIDUE flag after the PCM component has been registered. This becomes necessary when querying whether the dmaengine driver supports residue reporting from the dmaengine driver itself since the DMA channel might only be requested after the PCM component has been registered.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- New in v2 --- sound/soc/soc-generic-dmaengine-pcm.c | 39 ++++++++++++++--------------------- 1 file changed, 15 insertions(+), 24 deletions(-)
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 2a6c569..4e2bed8 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -248,6 +248,18 @@ err_free: return ret; }
+static snd_pcm_uframes_t dmaengine_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); + + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) + return snd_dmaengine_pcm_pointer_no_residue(substream); + else + return snd_dmaengine_pcm_pointer(substream); +} + static const struct snd_pcm_ops dmaengine_pcm_ops = { .open = dmaengine_pcm_open, .close = snd_dmaengine_pcm_close, @@ -255,7 +267,7 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { .hw_params = dmaengine_pcm_hw_params, .hw_free = snd_pcm_lib_free_pages, .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer, + .pointer = dmaengine_pcm_pointer, };
static const struct snd_soc_platform_driver dmaengine_pcm_platform = { @@ -265,23 +277,6 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = { .probe_order = SND_SOC_COMP_ORDER_LATE, };
-static const struct snd_pcm_ops dmaengine_no_residue_pcm_ops = { - .open = dmaengine_pcm_open, - .close = snd_dmaengine_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = dmaengine_pcm_hw_params, - .hw_free = snd_pcm_lib_free_pages, - .trigger = snd_dmaengine_pcm_trigger, - .pointer = snd_dmaengine_pcm_pointer_no_residue, -}; - -static const struct snd_soc_platform_driver dmaengine_no_residue_pcm_platform = { - .ops = &dmaengine_no_residue_pcm_ops, - .pcm_new = dmaengine_pcm_new, - .pcm_free = dmaengine_pcm_free, - .probe_order = SND_SOC_COMP_ORDER_LATE, -}; - static const char * const dmaengine_pcm_dma_channel_names[] = { [SNDRV_PCM_STREAM_PLAYBACK] = "tx", [SNDRV_PCM_STREAM_CAPTURE] = "rx", @@ -374,12 +369,8 @@ int snd_dmaengine_pcm_register(struct device *dev, if (ret) goto err_free_dma;
- if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) - ret = snd_soc_add_platform(dev, &pcm->platform, - &dmaengine_no_residue_pcm_platform); - else - ret = snd_soc_add_platform(dev, &pcm->platform, - &dmaengine_pcm_platform); + ret = snd_soc_add_platform(dev, &pcm->platform, + &dmaengine_pcm_platform); if (ret) goto err_free_dma;
The dmaengine framework now exposes the granularity with which it is able to report the transfer residue for a specific DMA channel. Check the granularity in the generic dmaengine PCM driver and a) Set the SNDRV_PCM_INFO_BATCH if the granularity is per period or worse. b) Fallback to the (race condition prone) period counting if the driver does not support any residue reporting.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- Changes since v1: * Add support for auto-detecting the NO_RESIDUE flag to the compat path --- sound/soc/soc-generic-dmaengine-pcm.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 4e2bed8..560a778 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -144,6 +144,8 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea if (ret == 0) { if (dma_caps.cmd_pause) hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; + if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) + hw.info |= SNDRV_PCM_INFO_BATCH; }
return snd_soc_set_runtime_hwparams(substream, &hw); @@ -187,6 +189,21 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel( dma_data->filter_data); }
+static bool dmaengine_pcm_can_report_residue(struct dma_chan *chan) +{ + struct dma_slave_caps dma_caps; + int ret; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret != 0) + return true; + + if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR) + return false; + + return true; +} + static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) { struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); @@ -239,6 +256,16 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) max_buffer_size); if (ret) goto err_free; + + /* + * This will only return false if we know for sure that at least + * one channel does not support residue reporting. If the DMA + * driver does not implement the slave_caps API we rely having + * the NO_RESIDUE flag set manually in case residue reporting is + * not supported. + */ + if (!dmaengine_pcm_can_report_residue(pcm->chan[i])) + pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE; }
return 0;
The pl330 driver properly reports that it does not have residue reporting support, which means the PCM dmaengine driver is able to figure this out on its own. So there is no need to set the flag manually. Removing the flag has the advantage that once the pl330 driver gains support for residue reporting it will automatically be used by the generic dmaengine PCM driver.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- New in v2 --- sound/soc/adi/axi-i2s.c | 3 +-- sound/soc/adi/axi-spdif.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/sound/soc/adi/axi-i2s.c b/sound/soc/adi/axi-i2s.c index 7f91a86..6058c1f 100644 --- a/sound/soc/adi/axi-i2s.c +++ b/sound/soc/adi/axi-i2s.c @@ -236,8 +236,7 @@ static int axi_i2s_probe(struct platform_device *pdev) if (ret) goto err_clk_disable;
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, - SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) goto err_clk_disable;
diff --git a/sound/soc/adi/axi-spdif.c b/sound/soc/adi/axi-spdif.c index 8db7a99..198e3a4 100644 --- a/sound/soc/adi/axi-spdif.c +++ b/sound/soc/adi/axi-spdif.c @@ -229,8 +229,7 @@ static int axi_spdif_probe(struct platform_device *pdev) if (ret) goto err_clk_disable;
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, - SND_DMAENGINE_PCM_FLAG_NO_RESIDUE); + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); if (ret) goto err_clk_disable;
The Samsung dmaengine ASoC driver is used with two different dmaengine drivers. The pl80x, which properly supports residue reporting and the pl330, which reports that it does not support residue reporting. So there is no need to manually set the NO_RESIDUE flag. This has the advantage that a proper (race condition free) PCM pointer() implementation is used when the pl80x driver is used. Also once the pl330 driver supports residue reporting the ASoC PCM driver will automatically start using it.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de Cc: Sangbeom Kim sbkim73@samsung.com --- New in v2 --- sound/soc/samsung/dmaengine.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 3be479d..750ce58 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -68,7 +68,6 @@ int samsung_asoc_dma_platform_register(struct device *dev) { return snd_dmaengine_pcm_register(dev, &samsung_dmaengine_pcm_config, SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME | - SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | SND_DMAENGINE_PCM_FLAG_COMPAT); } EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
On Mon, Jan 06, 2014 at 11:45:56AM +0100, Lars-Peter Clausen wrote:
Here is an updated version of the DMA residue granularity patchset. As discuessed last time it would be best if this could go through ASoC tree. It needs some feedback from the DMA folks first though.
I'm OK with the ASoC bits of this.
On Mon, Jan 06, 2014 at 11:45:56AM +0100, Lars-Peter Clausen wrote:
Here is an updated version of the DMA residue granularity patchset. As discuessed last time it would be best if this could go through ASoC tree. It needs some feedback from the DMA folks first though.
New in v2:
- Dropped byte level granularity as discussed during v1 review
- Added support for auto-detecting the NO_RESIDUE flag on the compat path in the generic ASoC dmaengine PCM driver
- Updated a few ASoC drivers to take advantage of the new API
Apart from cosmetic comments, the series looks fine to me. So if you guys want to merge this or update, am fine with either
so Acked-by: Vinod Koul vinod.koul@intel.com
-- ~Vinod
Updated original cover text from v1 below:
This patch series introduces a new field to the dma_slave_caps struct which exposes the granularity with which the reported residue is updated, updates the pl330 DMA driver to set this field and lets the generic dmaengine PCM audio driver check that field.
The reason for introducing the field is that for audio we need to know the granularity with which the reported residue is updated. The uncertainty of the ALSA period pointer depends on the granularity of the reported residue. E.g. if residue is only updated once every period this means that the position in the buffer from/to which the hardware is currently reading/writing could be anywhere between the reported PCM pointer and the reported PCM pointer plus one period size (plus some extra margin for interrupt latency, etc). Certain algorithms (e.g. pulseaudio's timer based scheduling) only work correctly if the uncertainty of the PCM pointer is low enough. Exposing this information from the DMA driver makes it possible for applications to switch to alternative modes of operation which also work with a high granularity.
The patch series introduces four levels of granularity, which I think will cover most DMA cores. I'd like some feedback though if anybody can think of a DMA controller for which none of the levels would be correct. The four levels are:
- DESCRIPTOR: The DMA channel is only able to tell whether a descriptor has been completed or not, which means residue reporting is not supported by this channel. The residue field of the dma_tx_state field will always be 0.
- SEGMENT: The DMA channel updates the residue field after each successfully completed segment of the transfer (For cyclic transfers this is after each period). This is typically implemented by having the hardware generate an interrupt after each transferred segment and then the driver updates the outstanding residue by the size of the segment. Another possibility is if the hardware supports SG and the segment descriptor has a field which gets set by the hardware after the segment has been completed. The driver then counts the number of segments which do not have the flag set to compute the residue.
- BURST: The DMA channel updates the residue field after each transferred burst. This is typically only supported if the hardware has a progress register of some sort (E.g. a register with the current read/write address or a register with the amount of bursts/beats/bytes that have been transferred or still need to be transferred).
- Lars
Lars-Peter Clausen (6): dma: Indicate residue granularity in dma_slave_caps dma: pl330: Set residue_granularity ASoC: generic-dmaengine-pcm: Check NO_RESIDUE flag at runtime ASoC: generic-dmaengine-pcm: Check DMA residue granularity ASoC: axi-{spdif,i2s}: Drop NO_RESIDUE flag ASoC: samsung: Remove NO_RESIDUE flag
drivers/dma/pl330.c | 1 + include/linux/dmaengine.h | 15 ++++++++ sound/soc/adi/axi-i2s.c | 3 +- sound/soc/adi/axi-spdif.c | 3 +- sound/soc/samsung/dmaengine.c | 1 - sound/soc/soc-generic-dmaengine-pcm.c | 66 ++++++++++++++++++++++------------- 6 files changed, 60 insertions(+), 29 deletions(-)
-- 1.8.0
-- To unsubscribe from this list: send the line "unsubscribe dmaengine" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
--
participants (3)
-
Lars-Peter Clausen
-
Mark Brown
-
Vinod Koul