Commit b9faf1f8 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

kernel: unified readout buffer for all carriers. Dummy API for WR

parent b7de3eb5
......@@ -85,8 +85,6 @@ struct ft_carrier_specific {
int (*init) (struct fmctdc_dev *);
int (*reset_core) (struct fmctdc_dev *);
int (*copy_timestamps) (struct fmctdc_dev *, int base_addr, int size,
void *dst);
void (*exit) (struct fmctdc_dev *);
};
......@@ -139,7 +137,6 @@ struct fmctdc_dev {
int ft_core_base;
int ft_i2c_base;
int ft_owregs_base;
int ft_dma_base;
int ft_carrier_base;
int ft_irq_base;
int ft_buffer_base;
......@@ -168,10 +165,9 @@ struct fmctdc_dev {
/* output lots of debug stuff? */
int verbose;
struct ft_channel_state channels[FT_NUM_CHANNELS];
int flags;
/* hardware buffer pointers / dacapo regs */
uint32_t cur_wr_ptr, prev_wr_ptr;
/* DMA buffer */
struct ft_hw_timestamp *raw_events;
};
extern struct ft_carrier_specific ft_carrier_spec;
......
......@@ -203,14 +203,6 @@ int ft_probe(struct fmc_device *fmc)
return -ENOMEM;
}
ft->raw_events =
kzalloc(sizeof(struct ft_hw_timestamp) * FT_BUFFER_EVENTS,
GFP_KERNEL);
if (!ft->raw_events) {
dev_err(dev, "can't allocate buffer\n");
return -ENOMEM;
}
index = fmc->op->validate(fmc, &ft_drv);
if (index < 0) {
dev_info(dev, "not using \"%s\" according to "
......@@ -291,8 +283,6 @@ int ft_probe(struct fmc_device *fmc)
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x602, fmc->slot_id + 1,
NULL);
ft->ft_dma_base = fmc_find_sdb_device(fmc->sdb, 0xce42, 0x601, NULL);
ft->ft_buffer_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x601, fmc->slot_id,
NULL);
......
......@@ -30,6 +30,22 @@
static void ft_readout_tasklet(unsigned long arg);
static void copy_timestamps(struct fmctdc_dev *ft, int base_addr, int size, void *dst)
{
int i;
uint32_t addr;
uint32_t *dptr;
BUG_ON(size & 3 || base_addr & 3); /* no unaligned reads, please. */
/* FIXME: use SDB to determine buffer base address (after fixing the HDL) */
addr = ft->ft_buffer_base + base_addr;
for (i = 0, dptr = (uint32_t *) dst; i < size / 4; i++, dptr++)
*dptr = fmc_readl(ft->fmc, addr + i * 4);
}
int ft_read_sw_fifo(struct fmctdc_dev *ft, int channel,
struct zio_channel *chan)
{
......@@ -122,7 +138,7 @@ static inline void process_timestamp(struct fmctdc_dev *ft,
/* first, convert the timestamp from the HDL units (81 ps bins)
to the WR format (where fractional part is 8 ns rescaled to 4096 units) */
ts.channel = channel;
ts.seconds = hwts->utc;
frac = hwts->bins * 81 * 64 / 125; /* 64/125 = 4096/8000: reduce fraction to avoid 64-bit division */
......@@ -153,6 +169,7 @@ static inline void process_timestamp(struct fmctdc_dev *ft,
if (likely
(diff.seconds || diff.coarse > 12
|| (diff.coarse == 12 && diff.frac >= 2048))) {
ts = st->prev_ts;
ft_ts_apply_offset(&ts,
ft->calib.
zero_offset[channel - 1]);
......@@ -245,16 +262,6 @@ static void ft_readout_tasklet(unsigned long arg)
ft->prev_wr_ptr = ft->cur_wr_ptr;
ft->cur_wr_ptr = ft_readl(ft, TDC_REG_BUFFER_PTR);
/* read the timestamps via DMA - we read the whole buffer, it doesn't really matter
for the HW if it's 16 bytes or a 4k page */
if (ft->carrier_specific->copy_timestamps(ft, 0,
FT_BUFFER_EVENTS *
sizeof(struct
ft_hw_timestamp),
ft->raw_events) < 0)
return; /* we can do nothing about this */
dacapo = check_lost_events(ft->cur_wr_ptr, ft->prev_wr_ptr, &count);
/* Start reading from the oldest event */
......@@ -264,7 +271,10 @@ static void ft_readout_tasklet(unsigned long arg)
rd_ptr = (ft->prev_wr_ptr >> 4) & 0x000ff; /* The oldest is prev_wr_ptr */
for (; count > 0; count--) {
process_timestamp(ft, &ft->raw_events[rd_ptr], dacapo);
struct ft_hw_timestamp hwts;
copy_timestamps( ft, rd_ptr * sizeof(struct ft_hw_timestamp),
sizeof(struct ft_hw_timestamp), &hwts );
process_timestamp(ft, &hwts, dacapo);
rd_ptr = (rd_ptr + 1) % FT_BUFFER_EVENTS;
}
......
......@@ -18,32 +18,6 @@
#include "hw/tdc_regs.h"
struct ft_spec_data {
void *buffer;
dma_addr_t dma_addr;
size_t buffer_size;
};
static inline uint32_t dma_readl(struct fmctdc_dev *ft, unsigned long reg)
{
return fmc_readl(ft->fmc, ft->ft_dma_base + reg);
}
static inline void dma_writel(struct fmctdc_dev *ft, uint32_t v,
unsigned long reg)
{
fmc_writel(ft->fmc, v, ft->ft_dma_base + reg);
}
static int ft_spec_init(struct fmctdc_dev *ft)
{
ft->carrier_data = kzalloc(sizeof(struct ft_spec_data), GFP_KERNEL);
if (!ft->carrier_data)
return -ENOMEM;
return 0;
}
static int ft_spec_reset(struct fmctdc_dev *ft)
{
struct spec_dev *spec = (struct spec_dev *)ft->fmc->carrier_data;
......@@ -69,84 +43,7 @@ static int ft_spec_reset(struct fmctdc_dev *ft)
return 0;
}
static int ft_spec_copy_timestamps(struct fmctdc_dev *ft, int base_addr,
int size, void *dst)
{
struct ft_spec_data *cspec = ft->carrier_data;
uint32_t status;
int i, ret = 0;
cspec->dma_addr =
dma_map_single(ft->fmc->hwdev, (char *)dst, size, DMA_FROM_DEVICE);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)
if (dma_mapping_error(cspec->dma_addr)) {
#else
if (dma_mapping_error(ft->fmc->hwdev, cspec->dma_addr)) {
#endif
dev_err(&ft->fmc->dev, "dma_map_single failed\n");
return -ENOMEM;
}
dma_writel(ft, 0, TDC_REG_DMA_CTRL);
dma_writel(ft, base_addr, TDC_REG_DMA_C_START);
dma_writel(ft, cspec->dma_addr & 0xffffffff, TDC_REG_DMA_H_START_L);
dma_writel(ft, ((uint64_t) cspec->dma_addr >> 32) & 0x00ffffffff,
TDC_REG_DMA_H_START_H);
dma_writel(ft, 0, TDC_REG_DMA_NEXT_L);
dma_writel(ft, 0, TDC_REG_DMA_NEXT_H);
/* Write the DMA length */
dma_writel(ft, size, TDC_REG_DMA_LEN);
/* No chained xfers, PCIe to host */
dma_writel(ft, 0, TDC_REG_DMA_ATTRIB);
/* Start the transfer */
dma_writel(ft, 1, TDC_REG_DMA_CTRL);
udelay(1);
dma_writel(ft, 0, TDC_REG_DMA_CTRL);
/* Don't bother about end-of-DMA IRQ, it only makes the driver unnecessarily complicated. */
for (i = 0; i < 1000; i++) {
status = dma_readl(ft, TDC_REG_DMA_STAT) & TDC_DMA_STAT_MASK;
if (status == TDC_DMA_STAT_DONE) {
ret = 0;
break;
} else if (status == TDC_DMA_STAT_ERROR) {
ret = -EIO;
break;
}
udelay(1);
}
if (i == 1000) {
dev_err(&ft->fmc->dev,
"%s: DMA transfer taking way too long. Something's really weird.\n",
__func__);
ret = -EIO;
}
dma_sync_single_for_cpu(ft->fmc->hwdev, cspec->dma_addr, size,
DMA_FROM_DEVICE);
dma_unmap_single(ft->fmc->hwdev, cspec->dma_addr, size,
DMA_FROM_DEVICE);
return ret;
}
static void ft_spec_exit(struct fmctdc_dev *ft)
{
kfree(ft->carrier_data);
}
struct ft_carrier_specific ft_carrier_spec = {
FT_GATEWARE_SPEC,
ft_spec_init,
ft_spec_reset,
ft_spec_copy_timestamps,
ft_spec_exit,
ft_spec_reset
};
......@@ -20,18 +20,6 @@
#include "hw/tdc_regs.h"
/*
static int ft_poll_interval = 200;
module_param_named(poll_interval, ft_poll_interval, int, 0444);
MODULE_PARM_DESC(poll_interval,
"Buffer polling interval in milliseconds. Applies to SVEC version only.");
*/
static int ft_svec_init(struct fmctdc_dev *ft)
{
return 0;
}
static int ft_svec_reset(struct fmctdc_dev *ft)
{
unsigned long tmo;
......@@ -66,6 +54,7 @@ static int ft_svec_reset(struct fmctdc_dev *ft)
return -EIO;
}
#if 0
static int ft_svec_copy_timestamps(struct fmctdc_dev *ft, int base_addr,
int size, void *dst)
{
......@@ -84,15 +73,10 @@ static int ft_svec_copy_timestamps(struct fmctdc_dev *ft, int base_addr,
return 0;
}
#endif
static void ft_svec_exit(struct fmctdc_dev *ft)
{
}
struct ft_carrier_specific ft_carrier_svec = {
FT_GATEWARE_SVEC,
ft_svec_init,
ft_svec_reset,
ft_svec_copy_timestamps,
ft_svec_exit
ft_svec_reset
};
......@@ -62,6 +62,9 @@ enum ft_devtype {
FT_TYPE_INPUT
};
static int ft_wr_mode(struct fmctdc_dev *fd, int on);
static int ft_wr_query(struct fmctdc_dev *ft);
static enum ft_devtype __ft_get_type(struct device *dev)
{
struct zio_obj_head *head = to_zio_head(dev);
......@@ -256,16 +259,63 @@ static int ft_zio_conf_set(struct device *dev, struct zio_attribute *zattr,
case FT_CMD_SET_HOST_TIME:
return ft_set_host_time(ft);
case FT_CMD_WR_ENABLE:
return ft_wr_mode(ft, 1);
case FT_CMD_WR_DISABLE:
return ft_wr_mode(ft, 0);
case FT_CMD_WR_QUERY:
dev_warn(&ft->fmc->dev,
"%s: sorry, no White Rabbit support yet.", __func__);
return -ENOTSUPP;
return ft_wr_query(ft);
default:
return -EINVAL;
}
}
static int ft_wr_mode(struct fmctdc_dev *fd, int on)
{
#if 0
unsigned long flags;
uint32_t tcr;
spin_lock_irqsave(&ft->lock, flags);
// tcr = fd_readl(fd, FD_REG_TCR);
if (on) {
fd_writel(fd, FD_TCR_WR_ENABLE, FD_REG_TCR);
set_bit(FD_FLAG_WR_MODE, &fd->flags);
} else {
fd_writel(fd, 0, FD_REG_TCR);
clear_bit(FD_FLAG_WR_MODE, &fd->flags);
/* not white-rabbit: write default to DAC for VCXO */
fd_spi_xfer(fd, FD_CS_DAC, 24,
ft->calib.vcxo_default_tune & 0xffff, NULL);
}
spin_unlock_irqrestore(&fd->lock, flags);
if(! (tcr & FD_TCR_WR_PRESENT))
return -EOPNOTSUPP;
else if( ! (tcr & FD_TCR_WR_LINK))
return -ENOLINK;
else
return 0;
#endif
return 0;
}
static int ft_wr_query(struct fmctdc_dev *ft)
{
#if 0
int ena = test_bit(FD_FLAG_WR_MODE, &fd->flags);
if (!ena)
return -ENODEV;
if (! (fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LINK))
return -ENOLINK;
if (fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LOCKED)
return 0;
return -EAGAIN;
#endif
return 0;
}
/*
* The probe function receives a new zio_device, which is different from
* what we allocated (that one is the "hardwre" device) but has the
......
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