Skip to content
  • Lars-Peter Clausen's avatar
    dmaengine: Add transfer termination synchronization support · b36f09c3
    Lars-Peter Clausen authored
    
    
    The DMAengine API has a long standing race condition that is inherent to
    the API itself. Calling dmaengine_terminate_all() is supposed to stop and
    abort any pending or active transfers that have previously been submitted.
    Unfortunately it is possible that this operation races against a currently
    running (or with some drivers also scheduled) completion callback.
    
    Since the API allows dmaengine_terminate_all() to be called from atomic
    context as well as from within a completion callback it is not possible to
    synchronize to the execution of the completion callback from within
    dmaengine_terminate_all() itself.
    
    This means that a user of the DMAengine API does not know when it is safe
    to free resources used in the completion callback, which can result in a
    use-after-free race condition.
    
    This patch addresses the issue by introducing an explicit synchronization
    primitive to the DMAengine API called dmaengine_synchronize().
    
    The existing dmaengine_terminate_all() is deprecated in favor of
    dmaengine_terminate_sync() and dmaengine_terminate_async(). The former
    aborts all pending and active transfers and synchronizes to the current
    context, meaning it will wait until all running completion callbacks have
    finished. This means it is only possible to call this function from
    non-atomic context. The later function does not synchronize, but can still
    be used in atomic context or from within a complete callback. It has to be
    followed up by dmaengine_synchronize() before a client can free the
    resources used in a completion callback.
    
    In addition to this the semantics of the device_terminate_all() callback
    are slightly relaxed by this patch. It is now OK for a driver to only
    schedule the termination of the active transfer, but does not necessarily
    have to wait until the DMA controller has completely stopped. The driver
    must ensure though that the controller has stopped and no longer accesses
    any memory when the device_synchronize() callback returns.
    
    This was in part done since most drivers do not pay attention to this
    anyway at the moment and to emphasize that this needs to be done when the
    device_synchronize() callback is implemented. But it also helps with
    implementing support for devices where stopping the controller can require
    operations that may sleep.
    
    Signed-off-by: default avatarLars-Peter Clausen <lars@metafoo.de>
    Signed-off-by: default avatarVinod Koul <vinod.koul@intel.com>
    b36f09c3