summaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi
diff options
context:
space:
mode:
authorSpencer E. Olson <olsonse@umich.edu>2016-01-27 14:28:24 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-07 18:38:08 -0800
commit5b293beb2ef0c45cd3c0e00ce67930b5d3471c13 (patch)
treefd960d0b02fe80712d8370735856f8cba784d923 /drivers/staging/comedi
parentf08a28e65cbdf80b4b4da7e423c45ee7c3ef35ac (diff)
downloadlinux-5b293beb2ef0c45cd3c0e00ce67930b5d3471c13.tar.bz2
staging: comedi: mite: enable continuous regeneration of finite samples
This change enables the mite DMA controller to only transfer the amount of data needed by a command. By default, the old behavior of transferring the entire comedi DMA data buffer is still in effect. These changes allow a command to only transmit a limited portion of that data buffer as needed. This patch begins to reinterprets stop_arg when stop_src == TRIG_NONE to allow the user to specify the length of the buffer that should be repeated. The intent is to allow a user to have a specific buffer repeated as-is indefinitely. The contents of the DMA buffer can be left static or changed by the user via mmap access to the DMA buffer. If the contents are changed by the user, additional munging is not performed by the driver and only a single call to comedi_mark_buffer_written should be done. Signed-off-by: Spencer E. Olson <olsonse@umich.edu> Reviewed-by: Ian Abbott <abbotti@mev.co.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/comedi')
-rw-r--r--drivers/staging/comedi/drivers/mite.c72
-rw-r--r--drivers/staging/comedi/drivers/mite.h3
2 files changed, 66 insertions, 9 deletions
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index fa7ae2c04556..8f24702c3380 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -297,7 +297,6 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
{
struct comedi_async *async = s->async;
unsigned int n_links;
- int i;
if (ring->descriptors) {
dma_free_coherent(ring->hw_dev,
@@ -326,17 +325,58 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
}
ring->n_links = n_links;
- for (i = 0; i < n_links; i++) {
+ return mite_init_ring_descriptors(ring, s, n_links << PAGE_SHIFT);
+}
+EXPORT_SYMBOL_GPL(mite_buf_change);
+
+/*
+ * initializes the ring buffer descriptors to provide correct DMA transfer links
+ * to the exact amount of memory required. When the ring buffer is allocated in
+ * mite_buf_change, the default is to initialize the ring to refer to the entire
+ * DMA data buffer. A command may call this function later to re-initialize and
+ * shorten the amount of memory that will be transferred.
+ */
+int mite_init_ring_descriptors(struct mite_dma_descriptor_ring *ring,
+ struct comedi_subdevice *s,
+ unsigned int nbytes)
+{
+ struct comedi_async *async = s->async;
+ unsigned int n_full_links = nbytes >> PAGE_SHIFT;
+ unsigned int remainder = nbytes % PAGE_SIZE;
+ int i;
+
+ dev_dbg(s->device->class_dev,
+ "mite: init ring buffer to %u bytes\n", nbytes);
+
+ if ((n_full_links + (remainder > 0 ? 1 : 0)) > ring->n_links) {
+ dev_err(s->device->class_dev,
+ "mite: ring buffer too small for requested init\n");
+ return -ENOMEM;
+ }
+
+ /* We set the descriptors for all full links. */
+ for (i = 0; i < n_full_links; ++i) {
ring->descriptors[i].count = cpu_to_le32(PAGE_SIZE);
ring->descriptors[i].addr =
cpu_to_le32(async->buf_map->page_list[i].dma_addr);
ring->descriptors[i].next =
- cpu_to_le32(ring->descriptors_dma_addr + (i +
- 1) *
- sizeof(struct mite_dma_descriptor));
+ cpu_to_le32(ring->descriptors_dma_addr +
+ (i + 1) * sizeof(struct mite_dma_descriptor));
}
- ring->descriptors[n_links - 1].next =
- cpu_to_le32(ring->descriptors_dma_addr);
+
+ /* the last link is either a remainder or was a full link. */
+ if (remainder > 0) {
+ /* set the lesser count for the remainder link */
+ ring->descriptors[i].count = cpu_to_le32(remainder);
+ ring->descriptors[i].addr =
+ cpu_to_le32(async->buf_map->page_list[i].dma_addr);
+ /* increment i so that assignment below refs last link */
+ ++i;
+ }
+
+ /* Assign the last link->next to point back to the head of the list. */
+ ring->descriptors[i - 1].next = cpu_to_le32(ring->descriptors_dma_addr);
+
/*
* barrier is meant to insure that all the writes to the dma descriptors
* have completed before the dma controller is commanded to read them
@@ -344,7 +384,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring,
smp_wmb();
return 0;
}
-EXPORT_SYMBOL_GPL(mite_buf_change);
+EXPORT_SYMBOL_GPL(mite_init_ring_descriptors);
void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits)
@@ -552,6 +592,7 @@ int mite_sync_output_dma(struct mite_channel *mite_chan,
unsigned int old_alloc_count = async->buf_read_alloc_count;
u32 nbytes_ub, nbytes_lb;
int count;
+ bool finite_regen = (cmd->stop_src == TRIG_NONE && stop_count != 0);
/* read alloc as much as we can */
comedi_buf_read_alloc(s, async->prealloc_bufsz);
@@ -561,11 +602,24 @@ int mite_sync_output_dma(struct mite_channel *mite_chan,
nbytes_ub = mite_bytes_read_from_memory_ub(mite_chan);
if (cmd->stop_src == TRIG_COUNT && (int)(nbytes_ub - stop_count) > 0)
nbytes_ub = stop_count;
- if ((int)(nbytes_ub - old_alloc_count) > 0) {
+
+ if ((!finite_regen || stop_count > old_alloc_count) &&
+ ((int)(nbytes_ub - old_alloc_count) > 0)) {
dev_warn(s->device->class_dev, "mite: DMA underrun\n");
async->events |= COMEDI_CB_OVERFLOW;
return -1;
}
+
+ if (finite_regen) {
+ /*
+ * This is a special case where we continuously output a finite
+ * buffer. In this case, we do not free any of the memory,
+ * hence we expect that old_alloc_count will reach a maximum of
+ * stop_count bytes.
+ */
+ return 0;
+ }
+
count = nbytes_lb - async->buf_read_count;
if (count <= 0)
return 0;
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index c32d4e4ddccc..87534b07ec81 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -110,6 +110,9 @@ void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits);
int mite_buf_change(struct mite_dma_descriptor_ring *ring,
struct comedi_subdevice *s);
+int mite_init_ring_descriptors(struct mite_dma_descriptor_ring *ring,
+ struct comedi_subdevice *s,
+ unsigned int nbytes);
enum mite_registers {
/*