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