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