linux/drivers/staging/fwserial/dma_fifo.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0+ */
   2/*
   3 * DMA-able FIFO interface
   4 *
   5 * Copyright (C) 2012 Peter Hurley <peter@hurleysoftware.com>
   6 */
   7
   8#ifndef _DMA_FIFO_H_
   9#define _DMA_FIFO_H_
  10
  11/**
  12 * The design basis for the DMA FIFO is to provide an output side that
  13 * complies with the streaming DMA API design that can be DMA'd from directly
  14 * (without additional copying), coupled with an input side that maintains a
  15 * logically consistent 'apparent' size (ie, bytes in + bytes avail is static
  16 * for the lifetime of the FIFO).
  17 *
  18 * DMA output transactions originate on a cache line boundary and can be
  19 * variably-sized. DMA output transactions can be retired out-of-order but
  20 * the FIFO will only advance the output in the original input sequence.
  21 * This means the FIFO will eventually stall if a transaction is never retired.
  22 *
  23 * Chunking the output side into cache line multiples means that some FIFO
  24 * memory is unused. For example, if all the avail input has been pended out,
  25 * then the in and out markers are re-aligned to the next cache line.
  26 * The maximum possible waste is
  27 *     (cache line alignment - 1) * (max outstanding dma transactions)
  28 * This potential waste requires additional hidden capacity within the FIFO
  29 * to be able to accept input while the 'apparent' size has not been reached.
  30 *
  31 * Additional cache lines (ie, guard area) are used to minimize DMA
  32 * fragmentation when wrapping at the end of the FIFO. Input is allowed into the
  33 * guard area, but the in and out FIFO markers are wrapped when DMA is pended.
  34 */
  35
  36#define DMA_FIFO_GUARD 3   /* # of cache lines to reserve for the guard area */
  37
  38struct dma_fifo {
  39        unsigned int     in;
  40        unsigned int     out;           /* updated when dma is pended         */
  41        unsigned int     done;          /* updated upon dma completion        */
  42        struct {
  43                unsigned corrupt:1;
  44        };
  45        int              size;          /* 'apparent' size of fifo            */
  46        int              guard;         /* ofs of guard area                  */
  47        int              capacity;      /* size + reserved                    */
  48        int              avail;         /* # of unused bytes in fifo          */
  49        unsigned int     align;         /* must be power of 2                 */
  50        int              tx_limit;      /* max # of bytes per dma transaction */
  51        int              open_limit;    /* max # of outstanding allowed       */
  52        int              open;          /* # of outstanding dma transactions  */
  53        struct list_head pending;       /* fifo markers for outstanding dma   */
  54        void             *data;
  55};
  56
  57struct dma_pending {
  58        struct list_head link;
  59        void             *data;
  60        unsigned int     len;
  61        unsigned int     next;
  62        unsigned int     out;
  63};
  64
  65static inline void dp_mark_completed(struct dma_pending *dp)
  66{
  67        dp->data += 1;
  68}
  69
  70static inline bool dp_is_completed(struct dma_pending *dp)
  71{
  72        return (unsigned long)dp->data & 1UL;
  73}
  74
  75void dma_fifo_init(struct dma_fifo *fifo);
  76int dma_fifo_alloc(struct dma_fifo *fifo, int size, unsigned int align,
  77                   int tx_limit, int open_limit, gfp_t gfp_mask);
  78void dma_fifo_free(struct dma_fifo *fifo);
  79void dma_fifo_reset(struct dma_fifo *fifo);
  80int dma_fifo_in(struct dma_fifo *fifo, const void *src, int n);
  81int dma_fifo_out_pend(struct dma_fifo *fifo, struct dma_pending *pended);
  82int dma_fifo_out_complete(struct dma_fifo *fifo,
  83                          struct dma_pending *complete);
  84
  85/* returns the # of used bytes in the fifo */
  86static inline int dma_fifo_level(struct dma_fifo *fifo)
  87{
  88        return fifo->size - fifo->avail;
  89}
  90
  91/* returns the # of bytes ready for output in the fifo */
  92static inline int dma_fifo_out_level(struct dma_fifo *fifo)
  93{
  94        return fifo->in - fifo->out;
  95}
  96
  97/* returns the # of unused bytes in the fifo */
  98static inline int dma_fifo_avail(struct dma_fifo *fifo)
  99{
 100        return fifo->avail;
 101}
 102
 103/* returns true if fifo has max # of outstanding dmas */
 104static inline bool dma_fifo_busy(struct dma_fifo *fifo)
 105{
 106        return fifo->open == fifo->open_limit;
 107}
 108
 109/* changes the max size of dma returned from dma_fifo_out_pend() */
 110static inline int dma_fifo_change_tx_limit(struct dma_fifo *fifo, int tx_limit)
 111{
 112        tx_limit = round_down(tx_limit, fifo->align);
 113        fifo->tx_limit = max_t(int, tx_limit, fifo->align);
 114        return 0;
 115}
 116
 117#endif /* _DMA_FIFO_H_ */
 118