lkml.org 
[lkml]   [2009]   [Dec]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH] kfifo: add DMA capabilities
    From
    Date
    As requested by Shargorodsky Atal:

    This patch adds functions for DMA handling to the new kfifo API.

    To prepare a DMA one of the kfifo_dma_..._prepare() Funktions must be
    called. This results in a scatterlist structure which can passed to the
    kernel DMA functions.

    After the DMA transfer was finished, the corresponding
    kfifo_dma_..._finsh() function must be called to remove the transfered
    data from the fifo.

    These are the function which added new to the kfifo API:

    kfifo_dma_in_prepare()
    kfifo_dma_in_finish()
    Prepare and finish an incoming DMA.

    kfifo_dma_in_prepare_rec
    kfifo_dma_in_finish_rec
    Ditto for record fifo's

    kfifo_dma_out_prepare
    kfifo_dma_out_finish
    Prepare and finish for an outcoming DMA.

    kfifo_dma_out_prepare_rec
    kfifo_dma_out_finish_rec
    Ditto for record fifo's

    The patch-set is against current mm tree from 11-Dec-2009

    Greetings,
    Stefani

    Signed-off-by: Stefani Seibold <stefani@seibold.net>
    ---
    include/linux/kfifo.h | 21 ++++
    kernel/kfifo.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++
    2 files changed, 272 insertions(+)

    diff -u -N -r -p kfifo8/include/linux/kfifo.h kfifo9/include/linux/kfifo.h
    --- kfifo8/include/linux/kfifo.h 2009-11-26 16:46:48.826439335 +0100
    +++ kfifo9/include/linux/kfifo.h 2009-12-11 14:25:00.354439818 +0100
    @@ -43,6 +43,7 @@

    #include <linux/kernel.h>
    #include <linux/spinlock.h>
    +#include <linux/scatterlist.h>

    struct kfifo {
    unsigned char *buffer; /* the buffer holding the data */
    @@ -608,4 +609,24 @@ static inline __must_check unsigned int
    return (l > recsize) ? l - recsize : 0;
    }

    +extern unsigned int kfifo_dma_in_prepare(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents);
    +extern void kfifo_dma_in_finish(struct kfifo *fifo, unsigned int len);
    +
    +extern __must_check unsigned int kfifo_dma_out_prepare(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents, unsigned int len);
    +extern void kfifo_dma_out_finish(struct kfifo *fifo, unsigned int len);
    +
    +extern unsigned int kfifo_dma_in_prepare_rec(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents, unsigned int recsize);
    +extern void kfifo_dma_in_finish_rec(struct kfifo *fifo, unsigned int len,
    + unsigned int recsize);
    +
    +extern __must_check unsigned int kfifo_dma_out_prepare_rec(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents, unsigned int len,
    + unsigned int recsize);
    +extern void kfifo_dma_out_finish_rec(struct kfifo *fifo, unsigned int len,
    + unsigned int recsize);
    +
    #endif
    +
    diff -u -N -r -p kfifo8/kernel/kfifo.c kfifo9/kernel/kfifo.c
    --- kfifo8/kernel/kfifo.c 2009-10-19 21:41:44.508999764 +0200
    +++ kfifo9/kernel/kfifo.c 2009-12-11 14:24:58.283459728 +0100
    @@ -398,3 +398,254 @@ void __kfifo_skip_generic(struct kfifo *
    }
    EXPORT_SYMBOL(__kfifo_skip_generic);

    +/**
    + * kfifo_dma_in_prepare - setup a scatterlist for DMA input
    + * @fifo: the fifo to be used.
    + * @sgl: pointer to the scatterlist array.
    + * @nents: number of entries in the scatterlist array (should be 1 or 2).
    + *
    + * This function fills a scatterlist for DMA input.
    + * If parameter len is equal 0 the max. size of available data will be used.
    + * It returns the number of bytes which are available for the transfer.
    + *
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +unsigned int kfifo_dma_in_prepare(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents)
    +{
    + return kfifo_dma_in_prepare_rec(fifo, sgl, nents, 0);
    +}
    +EXPORT_SYMBOL(kfifo_dma_in_prepare);
    +
    +/**
    + * kfifo_dma_in_finish - finish a DMA IN operation
    + * @fifo: the fifo to be used.
    + * @len: number number of bytes to received.
    + *
    + * This function finish a DMA IN operation. The in counter will be updated by
    + * the len parameter. No error checking will be done.
    + *
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +void kfifo_dma_in_finish(struct kfifo *fifo, unsigned int len)
    +{
    + __kfifo_add_in(fifo, len);
    +}
    +EXPORT_SYMBOL(kfifo_dma_in_finish);
    +
    +/**
    + * kfifo_dma_out_prepare - setup a scatterlist for DMA output
    + * @fifo: the fifo to be used.
    + * @sgl: pointer to the scatterlist array.
    + * @nents: number of entries in the scatterlist array (should be 1 or 2).
    + * @len: number number of bytes to transfer.
    + *
    + * This function fills a scatterlist for DMA output which at most @n bytes to
    + * transfer.
    + * It returns the number of bytes which are available for the transfer.
    + *
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +unsigned int kfifo_dma_out_prepare(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents, unsigned int len)
    +{
    + return kfifo_dma_out_prepare_rec(fifo, sgl, nents, len, 0);
    +}
    +EXPORT_SYMBOL(kfifo_dma_out_prepare);
    +
    +/**
    + * kfifo_dma_out_finish - finish a DMA OUT operation
    + * @fifo: the fifo to be used.
    + * @len: number number of bytes transferd.
    + *
    + * This function finish a DMA OUT operation. The in counter will be updated by
    + * the len parameter. No error checking will be done.
    + *
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +void kfifo_dma_out_finish(struct kfifo *fifo, unsigned int len)
    +{
    + __kfifo_add_out(fifo, len);
    +}
    +EXPORT_SYMBOL(kfifo_dma_out_finish);
    +
    +/**
    + * kfifo_dma_in_prepare_rec - setup a scatterlist for DMA input
    + * @fifo: the fifo to be used.
    + * @sgl: pointer to the scatterlist array.
    + * @nents: number of entries in the scatterlist array (should be 1 or 2).
    + * @recsize: size of record field
    + *
    + * This function fills a scatterlist for DMA input.
    + * It returns the number of bytes which are available for the transfer.
    + *
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +unsigned int kfifo_dma_in_prepare_rec(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents, unsigned int recsize)
    +{
    + unsigned int len;
    + unsigned int n;
    + unsigned int avail;
    + unsigned int off;
    +
    + if (!nents)
    + BUG();
    +
    + avail = kfifo_avail_rec(fifo, recsize);
    +
    + if (!avail)
    + return 0;
    +
    + switch(recsize) {
    + case 0:
    + len = kfifo_size(fifo);
    + break;
    + case 1:
    + len = 255;
    + break;
    + default:
    + len = 65535;
    + break;
    + }
    +
    + if (len > avail)
    + len = avail;
    +
    + n = fifo->size - __kfifo_off(fifo, fifo->in);
    +
    + if (n > recsize) {
    + n -= recsize;
    + if (n > len)
    + n = len;
    + off = __kfifo_off(fifo, fifo->in + recsize);
    + if ((n != len) && (nents > 1)) {
    + sg_set_buf(sgl, fifo->buffer + off, n);
    + sgl++;
    +
    + off = 0;
    + n = len - n;
    + }
    + else
    + len = n;
    + }
    + else {
    + off = recsize - n;
    + n = len;
    + }
    + sg_set_buf(sgl, fifo->buffer + off, n);
    + sg_mark_end(sgl);
    +
    + return len;
    +}
    +EXPORT_SYMBOL(kfifo_dma_in_prepare_rec);
    +
    +/**
    + * kfifo_dma_in_finish_rec - finish a DMA IN operation
    + * @fifo: the fifo to be used.
    + * @len: number number of bytes received.
    + * @recsize: size of record field
    + *
    + * This function finish a DMA IN operation. The in counter will be updated by
    + * the len parameter. No error checking will be done.
    + *
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +void kfifo_dma_in_finish_rec(struct kfifo *fifo, unsigned int len,
    + unsigned int recsize)
    +{
    + if (!recsize)
    + __kfifo_poke_n(fifo, recsize, len);
    + __kfifo_add_in(fifo, len + recsize);
    +}
    +EXPORT_SYMBOL(kfifo_dma_in_finish_rec);
    +
    +/**
    + * kfifo_dma_out_rec - setup a scatterlist for DMA output
    + * @fifo: the fifo to be used.
    + * @sgl: pointer to the scatterlist array.
    + * @nents: number of entries in the scatterlist array (should be 1 or 2).
    + * @len: number number of bytes to transfer.
    + * @recsize: size of record field
    + *
    + * This function fills a scatterlist for DMA output which at most @n bytes to
    + * transfer.
    + * If parameter len is equal 0 the max. size of available data will be used.
    + * It returns the number of bytes which are available for the transfer.
    + *
    + * After the DMA transfer the fifo entry must be removed with
    + * kfifo_dma_out_finish_rec().
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +unsigned int kfifo_dma_out_prepare_rec(struct kfifo *fifo,
    + struct scatterlist *sgl, int nents, unsigned int len,
    + unsigned int recsize)
    +{
    + unsigned int n;
    + unsigned int size;
    + unsigned int off;
    +
    + if (!nents)
    + BUG();
    +
    + size = __kfifo_peek_generic(fifo, recsize);
    +
    + if (!len || len > size)
    + len = size;
    +
    + n = fifo->size - __kfifo_off(fifo, fifo->out);
    +
    + if (n > recsize) {
    + n -= recsize;
    + if (n > len)
    + n = len;
    + off = __kfifo_off(fifo, fifo->out + recsize);
    + if ((n != len) && (nents > 1)) {
    + sg_set_buf(sgl, fifo->buffer + off, n);
    + sgl++;
    +
    + off = 0;
    + n = len - n;
    + }
    + else
    + len = n;
    + }
    + else {
    + off = recsize - n;
    + n = len;
    + }
    + sg_set_buf(sgl, fifo->buffer + off, n);
    + sg_mark_end(sgl);
    +
    + return len;
    +}
    +EXPORT_SYMBOL(kfifo_dma_out_prepare_rec);
    +
    +/**
    + * kfifo_dma_out_finish_rec - finish a DMA OUT operation
    + * @fifo: the fifo to be used.
    + * @len: number number of bytes transferd.
    + * @recsize: size of record field
    + *
    + * This function finish a DMA OUT operation. The in counter will be updated by
    + * the len parameter. No error checking will be done.
    + *
    + * Note that with only one concurrent reader and one concurrent
    + * writer, you don't need extra locking to use these functions.
    + */
    +void kfifo_dma_out_finish_rec(struct kfifo *fifo, unsigned int len,
    + unsigned int recsize)
    +{
    + if (!recsize)
    + len = __kfifo_peek_n(fifo, recsize);
    + __kfifo_add_out(fifo, len + recsize);
    +}
    +EXPORT_SYMBOL(kfifo_dma_out_finish_rec);
    +



    \
     
     \ /
      Last update: 2009-12-11 14:39    [W:5.212 / U:0.144 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site