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