• Kuninori Morimoto's avatar
    dmaengine: rcar-dmac: use TCRB instead of TCR for residue · 73a47bd0
    Kuninori Morimoto authored
    SYS/RT/Audio DMAC includes independent data buffers for reading
    and writing. Therefore, the read transfer counter and write transfer
    counter have different values.
    TCR indicates read counter, and TCRB indicates write counter.
    The relationship is like below.
    
    	        TCR       TCRB
    	[SOURCE] -> [DMAC] -> [SINK]
    
    In the MEM_TO_DEV direction, what really matters is how much data has
    been written to the device. If the DMA is interrupted between read and
    write, then, the data doesn't end up in the destination, so shouldn't
    be counted. TCRB is thus the register we should use in this cases.
    
    In the DEV_TO_MEM direction, the situation is more complex. Both the
    read and write side are important. What matters from a data consumer
    point of view is how much data has been written to memory.
    On the other hand, if the transfer is interrupted between read and
    write, we'll end up losing data. It can also be important to report.
    
    In the MEM_TO_MEM direction, what matters is of course how much data
    has been written to memory from data consumer point of view.
    Here, because read and write have independent data buffers, it will
    take a while for TCR and TCRB to become equal. Thus we should check
    TCRB in this case, too.
    
    Thus, all cases we should check TCRB instead of TCR.
    
    Without this patch, Sound Capture has noise after PulseAudio support
    (= 07b7acb5 ("ASoC: rsnd: update pointer more accurate")), because
    the recorder will use wrong residue counter which indicates transferred
    from sound device, but in reality the data was not yet put to memory
    and recorder will record it.
    
    However, because DMAC is buffering data until it can be transferable
    size, TCRB might not be updated.
    For example, if consumer doesn't know how much data can be received,
    it requests enough size to DMAC. But in reality, it might receive very
    few data. In such case, DMAC just buffered it until transferable size,
    and no TCRB updated.
    
    In such case, this buffered data will be transferred if CHCR::DE bit was
    cleared, and this is happen if rcar_dmac_chan_halt(). In other word, it
    happen when consumer called dmaengine_terminate_all().
    
    Because of this behavior, it need to flush buffered data when it returns
    "residue" (= dmaengine_tx_status()).
    Otherwise, consumer might calculate wrong things if it called
    dmaengine_tx_status() and dmaengine_terminate_all() consecutively.
    Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
    Tested-by: default avatarHiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
    Tested-by: default avatarRyo Kodama <ryo.kodama.vz@renesas.com>
    Tested-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
    Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
    73a47bd0
rcar-dmac.c 51.9 KB