Commit 970514ba authored by Federico Vaga's avatar Federico Vaga

*: propagate the HW timestamp format to userspace

This avoids local processing of all timestamps during acquisition
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 9bbd8088
......@@ -62,14 +62,26 @@ enum ft_command {
FT_CMD_IDENTIFY_OFF
};
/* White Rabbit timestamp */
struct ft_wr_timestamp {
uint64_t seconds;
uint32_t coarse;
uint32_t frac;
uint32_t channel;
uint32_t hseq_id; /* hardware channel sequence id */
};
/* Hardware TDC timestamp */
struct ft_hw_timestamp {
uint32_t seconds; /* 1 second resolution */
uint32_t coarse; /* 8 ns resolution */
uint32_t frac; /* In ACAM bins (81 ps) */
uint32_t metadata; /* channel, polarity, etc. */
} __packed;
#define FT_HW_TS_META_CHN_MASK 0x7
#define FT_HW_TS_META_CHN_SHIFT 0
#define FT_HW_TS_META_CHN(_meta) ((_meta & FT_HW_TS_META_CHN_MASK) >> FT_HW_TS_META_CHN_SHIFT)
#define FT_HW_TS_META_POL_MASK 0x8
#define FT_HW_TS_META_POL_SHIFT 3
#define FT_HW_TS_META_POL(_meta) ((_meta & FT_HW_TS_META_POL_MASK) >> FT_HW_TS_META_POL_SHIFT)
#define FT_HW_TS_META_SEQ_MASK 0xFFFFFFF0
#define FT_HW_TS_META_SEQ_SHIFT 4
#define FT_HW_TS_META_SEQ(_meta) ((_meta & FT_HW_TS_META_SEQ_MASK) >> FT_HW_TS_META_SEQ_SHIFT)
/* rest of the file is kernel-only */
#ifdef __KERNEL__
......@@ -115,33 +127,13 @@ struct ft_calibration { /* All of these are big endian in the EEPROM */
int32_t wr_offset;
};
/* Hardware TDC timestamp */
struct ft_hw_timestamp {
uint32_t utc; /* 1 second resolution */
uint32_t coarse; /* 8 ns resolution */
uint32_t frac; /* In ACAM bins (81 ps) */
uint32_t metadata; /* channel, polarity, etc. */
} __packed;
#define FT_HW_TS_META_CHN_MASK 0x7
#define FT_HW_TS_META_CHN_SHIFT 0
#define FT_HW_TS_META_CHN(_meta) ((_meta & FT_HW_TS_META_CHN_MASK) >> FT_HW_TS_META_CHN_SHIFT)
#define FT_HW_TS_META_POL_MASK 0x8
#define FT_HW_TS_META_POL_SHIFT 3
#define FT_HW_TS_META_POL(_meta) ((_meta & FT_HW_TS_META_POL_MASK) >> FT_HW_TS_META_POL_SHIFT)
#define FT_HW_TS_META_SEQ_MASK 0xFFFFFFF0
#define FT_HW_TS_META_SEQ_SHIFT 4
#define FT_HW_TS_META_SEQ(_meta) ((_meta & FT_HW_TS_META_SEQ_MASK) >> FT_HW_TS_META_SEQ_SHIFT)
struct ft_channel_state {
unsigned long flags;
int delay_reference;
int32_t user_offset;
struct ft_wr_timestamp last_ts; /**< used to compute delay
struct ft_hw_timestamp last_ts; /**< used to compute delay
between pulses */
int active_buffer;
......@@ -232,8 +224,8 @@ int ft_read_temp(struct fmctdc_dev *ft, int verbose);
int ft_pll_init(struct fmctdc_dev *ft);
void ft_pll_exit(struct fmctdc_dev *ft);
void ft_ts_apply_offset(struct ft_wr_timestamp *ts, int32_t offset_picos);
void ft_ts_sub(struct ft_wr_timestamp *a, struct ft_wr_timestamp *b);
void ft_ts_apply_offset(struct ft_hw_timestamp *ts, int32_t offset_picos);
void ft_ts_sub(struct ft_hw_timestamp *a, struct ft_hw_timestamp *b);
void ft_set_tai_time(struct fmctdc_dev *ft, uint64_t seconds, uint32_t coarse);
void ft_get_tai_time(struct fmctdc_dev *ft, uint64_t * seconds,
......
......@@ -92,65 +92,33 @@ static void ft_irq_enable_restore(struct fmctdc_dev *ft)
* @ts timestamp
*/
static void ft_timestamp_apply_offsets(struct fmctdc_dev *ft,
struct ft_wr_timestamp *ts)
struct ft_hw_timestamp *hwts)
{
struct ft_channel_state *st = &ft->channels[ts->channel];
unsigned int chan = FT_HW_TS_META_CHN(hwts->metadata);
struct ft_channel_state *st = &ft->channels[chan];
ft_ts_apply_offset(ts, ft->calib.zero_offset[ts->channel]);
ft_ts_apply_offset(ts, -ft->calib.wr_offset);
ft_ts_apply_offset(hwts, ft->calib.zero_offset[chan]);
ft_ts_apply_offset(hwts, -ft->calib.wr_offset);
if (st->user_offset)
ft_ts_apply_offset(ts, st->user_offset);
}
/**
* It converts an hardware timestamp into our local representation
* @ft FmcTdc device instance
* @hwts timestamp
* @wrts timestamp
*/
static void __ft_timestamp_hw_to_wr(struct fmctdc_dev *ft,
struct ft_wr_timestamp *wrts,
struct ft_hw_timestamp *hwts)
{
wrts->channel = FT_HW_TS_META_CHN(hwts->metadata);
wrts->seconds = hwts->utc;
wrts->coarse = hwts->coarse;
wrts->frac = hwts->frac;
wrts->hseq_id = FT_HW_TS_META_SEQ(hwts->metadata);
}
/**
* It proccess a given timestamp and when it correspond to a pulse it
* converts the timestamp from the hardware format to the white rabbit format
*/
static void ft_timestamp_hw_to_wr(struct fmctdc_dev *ft,
struct ft_wr_timestamp *wrts,
struct ft_hw_timestamp *hwts)
{
__ft_timestamp_hw_to_wr(ft, wrts, hwts);
ft_timestamp_apply_offsets(ft, wrts);
ft_ts_apply_offset(hwts, st->user_offset);
}
/**
* It puts the given timestamp in the ZIO control
* @cset ZIO cset instant
* @wrts the timestamp to convert
* @hwts the timestamp to convert
*/
static void ft_timestap_wr_to_zio(struct zio_cset *cset,
struct ft_wr_timestamp *wrts)
struct ft_hw_timestamp *hwts)
{
struct zio_device *zdev = cset->zdev;
struct fmctdc_dev *ft = zdev->priv_d;
struct zio_control *ctrl;
struct zio_ti *ti = cset->ti;
uint32_t *v;
struct ft_wr_timestamp ts = *wrts, *reflast;
struct ft_hw_timestamp ts = *hwts, *reflast;
struct ft_channel_state *st;
dev_dbg(&ft->fmc->dev,
"Set in ZIO block ch %d: hseq %u: %llu %u %u\n",
ts.channel, ts.hseq_id, ts.seconds, ts.coarse, ts.frac);
st = &ft->channels[cset->index];
ctrl = cset->chan->current_ctrl;
......@@ -160,7 +128,7 @@ static void ft_timestap_wr_to_zio(struct zio_cset *cset,
* Update last time stamp of the current channel, with the current
* time-stamp
*/
memcpy(&st->last_ts, &ts, sizeof(struct ft_wr_timestamp));
memcpy(&st->last_ts, &ts, sizeof(struct ft_hw_timestamp));
/*
* If we are in delay mode, replace the time stamp with the delay from
......@@ -168,18 +136,18 @@ static void ft_timestap_wr_to_zio(struct zio_cset *cset,
*/
if (st->delay_reference) {
reflast = &ft->channels[st->delay_reference - 1].last_ts;
if (likely(ts.hseq_id > reflast->hseq_id)) {
if (likely(FT_HW_TS_META_SEQ(ts.metadata) > FT_HW_TS_META_SEQ(reflast->metadata))) {
ft_ts_sub(&ts, reflast);
v[FT_ATTR_TDC_DELAY_REF_SEQ] = reflast->hseq_id;
v[FT_ATTR_TDC_DELAY_REF_SEQ] = FT_HW_TS_META_SEQ(reflast->metadata);
} else {
/*
* It seems that we are not able to compute the delay.
* Inform the user by setting the time stamp to 0
*/
memset(&ts, 0, sizeof(struct ft_wr_timestamp));
memset(&ts, 0, sizeof(struct ft_hw_timestamp));
}
} else {
v[FT_ATTR_TDC_DELAY_REF_SEQ] = ts.hseq_id;
v[FT_ATTR_TDC_DELAY_REF_SEQ] = FT_HW_TS_META_SEQ(ts.metadata);
}
/* Write the timestamp in the trigger, it will reach the control */
......@@ -189,13 +157,13 @@ static void ft_timestap_wr_to_zio(struct zio_cset *cset,
/* Synchronize ZIO sequence number with ours (ZIO does +1 on this) */
ctrl->seq_num = ts.hseq_id - 1;
ctrl->seq_num = FT_HW_TS_META_SEQ(ts.metadata) - 1;
v[FT_ATTR_TDC_ZERO_OFFSET] = ft->calib.zero_offset[cset->index];
v[FT_ATTR_TDC_USER_OFFSET] = st->user_offset;
if (cset->chan->active_block) {
memcpy(cset->chan->active_block->data, wrts,
memcpy(cset->chan->active_block->data, hwts,
ctrl->nsamples * ctrl->ssize);
}
}
......@@ -282,7 +250,6 @@ static void ft_readout_dma_start(struct fmctdc_dev *ft, int channel)
struct ft_channel_state *st = &ft->channels[channel];
uint32_t base_cur;
struct ft_hw_timestamp *dma_buf;
struct ft_wr_timestamp wrts;
const int ts_per_page = PAGE_SIZE / TDC_BYTES_PER_TIMESTAMP;
unsigned int count, transfer;
struct zio_cset *cset;
......@@ -309,18 +276,18 @@ static void ft_readout_dma_start(struct fmctdc_dev *ft, int channel)
/* gn4124_dma_read(ft->fmc, 0, dma_buf, 16); */
for (i = 0; i < n; i++) {
ft_timestamp_hw_to_wr(ft, &wrts, &dma_buf[i]);
dev_info(&ft->fmc->dev, "Ts %x %x %x %x - %llx %x %x\n",
dma_buf[i].utc, dma_buf[i].coarse,
dma_buf[i].frac, dma_buf[i].metadata,
wrts.seconds, wrts.coarse, wrts.frac);
ft_timestamp_apply_offsets(ft, &dma_buf[i]);
dev_info(&ft->fmc->dev, "Ts %x %x %x %x\n",
dma_buf[i].seconds, dma_buf[i].coarse,
dma_buf[i].frac, dma_buf[i].metadata);
if (!(ZIO_TI_ARMED & cset->ti->flags)) {
dev_warn(&cset->head.dev,
"Time stamp lost, trigger was not armed\n");
break;
}
/* there is an active block, store data there */
ft_timestap_wr_to_zio(cset, &wrts);
ft_timestap_wr_to_zio(cset, &dma_buf[i]);
zio_trigger_data_done(cset);
}
......@@ -392,10 +359,9 @@ static void ft_readout_fifo_one(struct zio_cset *cset)
{
struct fmctdc_dev *ft = cset->zdev->priv_d;
struct ft_hw_timestamp hwts;
struct ft_wr_timestamp wrts;
ft_timestap_get(cset, &hwts, 0);
ft_timestamp_hw_to_wr(ft, &wrts, &hwts);
ft_timestamp_apply_offsets(ft, &hwts);
if (!(ZIO_TI_ARMED & cset->ti->flags)) {
dev_warn(&cset->head.dev,
......@@ -403,7 +369,7 @@ static void ft_readout_fifo_one(struct zio_cset *cset)
return; /* Nothing to do, ZIO was not ready */
}
/* there is an active block, store data there */
ft_timestap_wr_to_zio(cset, &wrts);
ft_timestap_wr_to_zio(cset, &hwts);
zio_trigger_data_done(cset);
}
......
......@@ -19,14 +19,14 @@
/* WARNING: the seconds register name is a bit misleading - it is not UTC time
as the core is not aware of leap seconds, making it TAI time. */
void ft_ts_from_picos(uint32_t picos, struct ft_wr_timestamp *result)
void ft_ts_from_picos(uint32_t picos, struct ft_hw_timestamp *result)
{
result->frac = (picos % 8000) * 4096 / 8000;
result->coarse = (picos / 8000);
result->seconds = 0;
}
void ft_ts_add(struct ft_wr_timestamp *a, struct ft_wr_timestamp *b)
void ft_ts_add(struct ft_hw_timestamp *a, struct ft_hw_timestamp *b)
{
a->frac += b->frac;
......@@ -45,7 +45,7 @@ void ft_ts_add(struct ft_wr_timestamp *a, struct ft_wr_timestamp *b)
a->seconds += b->seconds;
}
void ft_ts_sub(struct ft_wr_timestamp *a, struct ft_wr_timestamp *b)
void ft_ts_sub(struct ft_hw_timestamp *a, struct ft_hw_timestamp *b)
{
int32_t d_frac, d_coarse = 0;
......@@ -68,9 +68,9 @@ void ft_ts_sub(struct ft_wr_timestamp *a, struct ft_wr_timestamp *b)
a->seconds -= b->seconds;
}
void ft_ts_apply_offset(struct ft_wr_timestamp *ts, int32_t offset_picos)
void ft_ts_apply_offset(struct ft_hw_timestamp *ts, int32_t offset_picos)
{
struct ft_wr_timestamp offset_ts;
struct ft_hw_timestamp offset_ts;
ft_ts_from_picos(offset_picos < 0 ? -offset_picos : offset_picos,
&offset_ts);
......
......@@ -320,7 +320,7 @@ static struct zio_channel ft_chan_tmpl = {
.raw_io = ft_zio_input,\
.chan_template = &ft_chan_tmpl,\
.n_chan = 1,\
.ssize = sizeof(struct ft_wr_timestamp), \
.ssize = sizeof(struct ft_hw_timestamp), \
.flags = ZIO_DISABLED | \
ZIO_DIR_INPUT | \
ZIO_CSET_SELF_TIMED, \
......
......@@ -602,6 +602,14 @@ int fmctdc_read_last(struct fmctdc_board *userb, unsigned int channel,
}
static void fmctdc_ts_convert(struct fmctdc_time *t, struct ft_hw_timestamp *o)
{
t->seconds = o->seconds;
t->coarse = o->coarse;
t->frac = o->frac;
t->seq_id = FT_HW_TS_META_SEQ(o->metadata);
}
/**
* It reads a given number of time-stamps from the driver. It will wait at
* most once and return the number of samples that it received from a given
......@@ -636,7 +644,7 @@ int fmctdc_read(struct fmctdc_board *userb, unsigned int channel,
uint32_t *attrs;
int i, j;
fd_set set;
struct ft_wr_timestamp data;
struct ft_hw_timestamp data;
if (channel >= FMCTDC_NUM_CHANNELS) {
errno = EINVAL;
......@@ -649,20 +657,16 @@ int fmctdc_read(struct fmctdc_board *userb, unsigned int channel,
return -1;
if (j == sizeof(ctrl)) {
/* one sample: pick it */
attrs = ctrl.attr_channel.ext_val;
t[i].seconds = ctrl.tstamp.secs;
t[i].coarse = ctrl.tstamp.ticks;
t[i].frac = ctrl.tstamp.bins;
t[i].seq_id = ctrl.seq_num;
t[i].ref_gseq_id = attrs[FT_ATTR_TDC_DELAY_REF_SEQ];
i++;
assert(sizeof(data) == ctrl.nsamples * ctrl.ssize);
if (sizeof(data) == ctrl.nsamples * ctrl.ssize) {
j = read(b->fdd[channel], &data,
ctrl.nsamples * ctrl.ssize);
if (j == ctrl.nsamples * ctrl.ssize)
if (j == ctrl.nsamples * ctrl.ssize) {
fmctdc_ts_convert(&t[i], &data);
attrs = ctrl.attr_channel.ext_val;
t[i].ref_gseq_id = attrs[FT_ATTR_TDC_DELAY_REF_SEQ];
continue; /* Everything is fine */
}
}
errno = EIO;
......
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