Commit 38d143d9 authored by Alessandro Rubini's avatar Alessandro Rubini

kernel/fd-irq.c: split between hw and sw fifo

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent c1954466
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/zio.h> #include <linux/zio.h>
...@@ -53,29 +54,26 @@ static void fd_ts_sub(struct fd_time *t, uint64_t pico) ...@@ -53,29 +54,26 @@ static void fd_ts_sub(struct fd_time *t, uint64_t pico)
} }
} }
int fd_read_fifo(struct fd_dev *fd, struct zio_channel *chan) /* This is called from outside, too */
int fd_read_sw_fifo(struct fd_dev *fd, struct zio_channel *chan)
{ {
struct zio_control *ctrl; struct zio_control *ctrl;
uint32_t *v, reg; uint32_t *v;
int i;
struct fd_time t; struct fd_time t;
unsigned long flags;
if ((fd_readl(fd, FD_REG_TSBCR) & FD_TSBCR_EMPTY))
return -EAGAIN;
if (!chan->active_block) if (!chan->active_block)
return -EAGAIN; return -EAGAIN;
if (fd->sw_fifo.tail == fd->sw_fifo.head)
return -EAGAIN;
/* Fecth the fifo entry to registers, so we can read them */ /* Copy the sample to local storage */
fd_writel(fd, FD_TSBR_ADVANCE_ADV, FD_REG_TSBR_ADVANCE); spin_lock_irqsave(&fd->lock, flags);
i = fd->sw_fifo.tail & (fd_sw_fifo_len - 1);
/* First, read input data into a local struct to fix the offset */ t = fd->sw_fifo.t[i];
t.utc = fd_readl(fd, FD_REG_TSBR_SECH) & 0xff; fd->sw_fifo.tail++;
t.utc <<= 32; spin_unlock_irqrestore(&fd->lock, flags);
t.utc |= fd_readl(fd, FD_REG_TSBR_SECL);
t.coarse = fd_readl(fd, FD_REG_TSBR_CYCLES) & 0xfffffff;
reg = fd_readl(fd, FD_REG_TSBR_FID);
t.frac = FD_TSBR_FID_FINE_R(reg);
t.channel = FD_TSBR_FID_CHANNEL_R(reg);
t.seq_id = FD_TSBR_FID_SEQID_R(reg);
/* The coarse count may be negative, because of how it works */ /* The coarse count may be negative, because of how it works */
if (t.coarse & (1<<27)) { // coarse is 28 bits if (t.coarse & (1<<27)) { // coarse is 28 bits
...@@ -111,6 +109,49 @@ int fd_read_fifo(struct fd_dev *fd, struct zio_channel *chan) ...@@ -111,6 +109,49 @@ int fd_read_fifo(struct fd_dev *fd, struct zio_channel *chan)
return 0; return 0;
} }
/* This is local: reads the hw fifo and stores to the sw fifo */
static int fd_read_hw_fifo(struct fd_dev *fd)
{
uint32_t reg;
struct fd_time *t;
unsigned long flags;
signed long diff;
if ((fd_readl(fd, FD_REG_TSBCR) & FD_TSBCR_EMPTY))
return -EAGAIN;
t = fd->sw_fifo.t;
t += fd->sw_fifo.head & (fd_sw_fifo_len - 1);
/* Fetch the fifo entry to registers, so we can read them */
fd_writel(fd, FD_TSBR_ADVANCE_ADV, FD_REG_TSBR_ADVANCE);
/* Read input data into the sofware fifo */
t->utc = fd_readl(fd, FD_REG_TSBR_SECH) & 0xff;
t->utc <<= 32;
t->utc |= fd_readl(fd, FD_REG_TSBR_SECL);
t->coarse = fd_readl(fd, FD_REG_TSBR_CYCLES) & 0xfffffff;
reg = fd_readl(fd, FD_REG_TSBR_FID);
t->frac = FD_TSBR_FID_FINE_R(reg);
t->channel = FD_TSBR_FID_CHANNEL_R(reg);
t->seq_id = FD_TSBR_FID_SEQID_R(reg);
/* Then, increment head and make some checks */
spin_lock_irqsave(&fd->lock, flags);
diff = fd->sw_fifo.head - fd->sw_fifo.tail;
fd->sw_fifo.head++;
if (diff >= fd_sw_fifo_len)
fd->sw_fifo.tail += fd_sw_fifo_len / 2;
spin_unlock_irqrestore(&fd->lock, flags);
BUG_ON(diff < 0);
if (diff >= fd_sw_fifo_len)
dev_warn(fd->fmc->hwdev, "Fifo overlow, dropped %i samples\n",
fd_sw_fifo_len / 2);
return 0;
}
/* /*
* We have a timer, used to poll for input samples, until the interrupt * We have a timer, used to poll for input samples, until the interrupt
* is there. A timer duration of 0 selects the interrupt. * is there. A timer duration of 0 selects the interrupt.
...@@ -127,6 +168,10 @@ static void fd_timer_fn(unsigned long arg) ...@@ -127,6 +168,10 @@ static void fd_timer_fn(unsigned long arg)
struct zio_device *zdev = fd->zdev; struct zio_device *zdev = fd->zdev;
int i; int i;
/* Always read the hardware fifo until empty */
while (!fd_read_hw_fifo(fd))
;
if (zdev) { if (zdev) {
chan = zdev->cset[0].chan; chan = zdev->cset[0].chan;
} else { } else {
...@@ -134,12 +179,11 @@ static void fd_timer_fn(unsigned long arg) ...@@ -134,12 +179,11 @@ static void fd_timer_fn(unsigned long arg)
goto out; goto out;
} }
/* FIXME: manage an array of input samples */
if (!test_bit(FD_FLAG_INPUT_READY, &fd->flags)) if (!test_bit(FD_FLAG_INPUT_READY, &fd->flags))
goto out; goto out;
/* there is an active block, try reading fifo */ /* there is an active block, try reading an accumulated sample */
if (fd_read_fifo(fd, chan) == 0) { if (fd_read_sw_fifo(fd, chan) == 0) {
clear_bit(FD_FLAG_INPUT_READY, &fd->flags); clear_bit(FD_FLAG_INPUT_READY, &fd->flags);
chan->cset->trig->t_op->data_done(chan->cset); chan->cset->trig->t_op->data_done(chan->cset);
} }
......
...@@ -531,7 +531,7 @@ static int fd_zio_input(struct zio_cset *cset) ...@@ -531,7 +531,7 @@ static int fd_zio_input(struct zio_cset *cset)
set_bit(FD_FLAG_DO_INPUT, &fd->flags); set_bit(FD_FLAG_DO_INPUT, &fd->flags);
} }
/* Ready for input. If there's already something, return it now */ /* Ready for input. If there's already something, return it now */
if (fd_read_fifo(fd, cset->chan) == 0) { if (fd_read_sw_fifo(fd, cset->chan) == 0) {
return 0; /* don't call data_done, let the caller do it */ return 0; /* don't call data_done, let the caller do it */
} }
/* Mark the active block is valid, and return EAGAIN */ /* Mark the active block is valid, and return EAGAIN */
......
...@@ -359,7 +359,7 @@ extern void fd_apply_offset(uint32_t *a, int32_t off_pico); ...@@ -359,7 +359,7 @@ extern void fd_apply_offset(uint32_t *a, int32_t off_pico);
/* Functions exported by fd-irq.c */ /* Functions exported by fd-irq.c */
struct zio_channel; struct zio_channel;
extern int fd_read_fifo(struct fd_dev *fd, struct zio_channel *chan); extern int fd_read_sw_fifo(struct fd_dev *fd, struct zio_channel *chan);
extern int fd_irq_init(struct fd_dev *fd); extern int fd_irq_init(struct fd_dev *fd);
extern void fd_irq_exit(struct fd_dev *fd); extern void fd_irq_exit(struct fd_dev *fd);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment