dma_fifo.h (4022B)
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_ */