• Russell King's avatar
    ARM: PL011: Add support for transmit DMA · 68b65f73
    Russell King authored
    Add DMA engine support for transmit to the PL011 driver.  Based on a
    patch from Linus Walliej, with the following changes:
    
    - remove RX DMA support.  As PL011 doesn't give us receive timeout
      interrupts, we only get notified of received data when the RX DMA
      has completed.  This rather sucks for interactive use of the TTY.
    
    - remove abuse of completions.  Completions are supposed to be for
      events, not to tell what condition buffers are in.  Replace it with
      a simple 'queued' bool.
    
    - fix locking - it is only safe to access the circular buffer with the
      port lock held.
    
    - only map the DMA buffer when required - if we're ever behind an IOMMU
      this helps keep IOMMU usage down, and also ensures that we're legal
      when we change the scatterlist entry length.
    
    - fix XON/XOFF sending - we must send XON/XOFF characters out as soon
      as possible - waiting for up to 4095 characters in the DMA buffer
      to be sent first is not acceptable.
    
    - fix XON/XOFF receive handling - we need to stop DMA when instructed
      to by the TTY layer, and restart it again when instructed to.  There
      is a subtle problem here: we must not completely empty the circular
      buffer with DMA, otherwise we will not be notified of XON.
    
    - change the 'enable_dma' flag into a 'using DMA' flag, and track
      whether we can use TX DMA by whether the channel pointer is non-NULL.
      This gives us more control over whether we use DMA in the driver.
    
    - we don't need to have the TX DMA buffer continually allocated for
      each port - instead, allocate it when the port starts up, and free
      it when it's shut down.  Update the 'using DMA' flag if we get
      the buffer, and adjust the TTY FIFO size appropriately.
    
    - if we're going to use PIO to send characters, use the existing IRQ
      based functionality rather than reimplementing it.  This also ensures
      we call uart_write_wakeup() at the appropriate time, otherwise we'll
      stall.
    
    - use DMA engine helper functions for type safety.
    
    - fix init when built as a module - we can't have to initcall functions,
      so we must settle on one.  This means we can eliminate the deferred
      DMA initialization.
    
    - there is no need to terminate transfers on a failed prep_slave_sg()
      call - nothing has been setup, so nothing needs to be terminated.
      This avoids a potential deadlock in the DMA engine code
      (tasklet->callback->failed prepare->terminate->tasklet_disable
       which then ends up waiting for the tasklet to finish running.)
    
    - Dan says that the submission callback should not return an error:
      | dma_submit_error() is something I should have removed after commit
      | a0587bcf "ioat1: move descriptor allocation from submit to prep" all
      | errors should be notified by prep failing to return a descriptor
      | handle.  Negative dma_cookie_t values are only returned by the
      | dma_async_memcpy* calls which translate a prep failure into -ENOMEM.
      So remove the error handling at that point.  This also solves the
      potential deadlock mentioned in the previous comment.
    Acked-by: default avatarLinus Walleij <linus.walleij@stericsson.com>
    Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
    68b65f73
amba-pl011.c 36.9 KB