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
38 struct 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
57 struct dma_pending {
58 struct list_head link;
59 void *data;
60 unsigned int len;
61 unsigned int next;
62 unsigned int out;
63 };
64
dp_mark_completed(struct dma_pending * dp)65 static inline void dp_mark_completed(struct dma_pending *dp)
66 {
67 dp->data += 1;
68 }
69
dp_is_completed(struct dma_pending * dp)70 static inline bool dp_is_completed(struct dma_pending *dp)
71 {
72 return (unsigned long)dp->data & 1UL;
73 }
74
75 void dma_fifo_init(struct dma_fifo *fifo);
76 int dma_fifo_alloc(struct dma_fifo *fifo, int size, unsigned int align,
77 int tx_limit, int open_limit, gfp_t gfp_mask);
78 void dma_fifo_free(struct dma_fifo *fifo);
79 void dma_fifo_reset(struct dma_fifo *fifo);
80 int dma_fifo_in(struct dma_fifo *fifo, const void *src, int n);
81 int dma_fifo_out_pend(struct dma_fifo *fifo, struct dma_pending *pended);
82 int dma_fifo_out_complete(struct dma_fifo *fifo,
83 struct dma_pending *complete);
84
85 /* returns the # of used bytes in the fifo */
dma_fifo_level(struct dma_fifo * fifo)86 static 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 */
dma_fifo_out_level(struct dma_fifo * fifo)92 static 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 */
dma_fifo_avail(struct dma_fifo * fifo)98 static 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 */
dma_fifo_busy(struct dma_fifo * fifo)104 static 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() */
dma_fifo_change_tx_limit(struct dma_fifo * fifo,int tx_limit)110 static 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