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