Commit 78bc0498 authored by Federico Vaga's avatar Federico Vaga

Merge branch '23-report-error-when-fpga-is-not-configured' into 'master'

Resolve "Report error when FPGA is not configured"

Closes #23

See merge request be-cem-edl/fec/hardware-modules/fmc-delay-1ns-8cha!15
parents 2e42bef3 cfc135b5
......@@ -513,6 +513,7 @@ static int __fd_zio_output(struct fd_dev *fd, int index1_4, uint32_t *attrs)
int mode = attrs[FD_ATTR_OUT_MODE];
int rep = attrs[FD_ATTR_OUT_REP];
int dcr = 0;
unsigned long timeout;
if (mode == FD_OUT_MODE_DELAY || mode == FD_OUT_MODE_DISABLED) {
if(rep < 0 || rep > 16) /* delay mode allows trains of 1 to 16 pulses. */
......@@ -629,6 +630,13 @@ static int __fd_zio_output(struct fd_dev *fd, int index1_4, uint32_t *attrs)
/* Update the time stamps according to start/end registers */
fd_ch_writel(fd, ch, dcr | FD_DCR_UPDATE, FD_REG_DCR);
timeout = jiffies + msecs_to_jiffies(10);
while (!(fd_ch_readl(fd, ch, FD_REG_DCR) & FD_DCR_UPD_DONE)) {
if (WARN_ON(time_after(jiffies, timeout)))
return -ETIMEDOUT;
cpu_relax();
}
/* Enable channel output */
if (mode == FD_OUT_MODE_DELAY) {
fd_ch_writel(fd, ch, dcr | FD_DCR_ENABLE, FD_REG_DCR);
......@@ -642,7 +650,7 @@ static int __fd_zio_output(struct fd_dev *fd, int index1_4, uint32_t *attrs)
/* This is called on user write */
static int fd_zio_output(struct zio_cset *cset)
{
int i;
int i, err;
struct fd_dev *fd;
struct zio_control *ctrl;
......@@ -656,7 +664,10 @@ static int fd_zio_output(struct zio_cset *cset)
printk("%08x%c", ctrl->attr_channel.ext_val[i],
i == FD_ATTR_OUT__LAST -1 ? '\n' : ' ');
}
return __fd_zio_output(fd, cset->index, ctrl->attr_channel.ext_val);
err = __fd_zio_output(fd, cset->index, ctrl->attr_channel.ext_val);
if (err)
cset->chan[0].current_ctrl->drv_alarms |= FD_ZIO_ALARM_FAIL_CONFIG;
return err;
}
/*
......
......@@ -162,6 +162,8 @@ struct fd_calibration { /* All of these are big endian */
uint32_t vcxo_default_tune;
};
#define FD_ZIO_ALARM_FAIL_CONFIG (1 << 0) /* Delay configuration failed */
#ifdef __KERNEL__ /* All the rest is only of kernel users */
#include <linux/spinlock.h>
#include <linux/timer.h>
......
......@@ -162,6 +162,8 @@ int fdelay_close(struct fdelay_board *userb)
for (j = 0; j < ARRAY_SIZE(b->fdc); j++) {
if (b->fdc[j] >= 0)
close(b->fdc[j]);
if (b->fda[j] != NULL)
fclose(b->fda[j]);
}
free(b->sysbase);
......@@ -219,6 +221,7 @@ float fdelay_read_temperature(struct fdelay_board *userb)
static const char *fdelay_error_string[] = {
[FDELAY_ERR_VERSION_MISMATCH - __FDELAY_ERR_MIN] =
"Incompatible version driver-library",
[FDELAY_ERR_CONFIG - __FDELAY_ERR_MIN] = "Failed to configure delay engine",
};
/**
......
......@@ -18,6 +18,7 @@ extern "C" {
#define __FDELAY_ERR_MIN 4096
enum fmctdc_error_numbers {
FDELAY_ERR_VERSION_MISMATCH = __FDELAY_ERR_MIN,
FDELAY_ERR_CONFIG,
__FDELAY_ERR_MAX,
};
......@@ -139,6 +140,7 @@ struct __fdelay_board {
char *devbase;
char *sysbase;
int fdc[5]; /* The 5 control channels */
FILE *fda[5]; /* The 5 channels' alarms */
};
static inline int fdelay_is_verbose(void)
......
......@@ -70,6 +70,50 @@ static int __fdelay_get_ch_fd(struct __fdelay_board *b,
return 0;
}
/**
* Get pending FMC Fine Delay channel alarms.
*
* Getting the alarms will also clear them.
*
* @param[in] userb device token
* @param[in] channel channel number in range [0, 3] ([1,4] on the front-panel)
* @param[out] zio_alarms the current zio alarms
* @param[out] drv_alarms the current drv alarms
* @return 0 when no alarms, otherwise -1 and errno is appropriately set
*/
static int fdelay_alarm_get(struct fdelay_board *userb, int channel,
uint8_t *zio_alarms, uint8_t *drv_alarms)
{
__define_board(b, userb);
int ch14 = channel + 1;
int ret;
if (channel < 0 || channel > 3) {
errno = EINVAL;
return -1;
}
if (b->fda[ch14] <= 0) {
char fname[128];
snprintf(fname, sizeof(fname),
"%s/fd-ch%i/chan0/alarms", b->sysbase, ch14);
b->fda[ch14] = fopen(fname, "r+");
if (b->fda[ch14] == NULL)
return -1;
}
rewind(b->fda[ch14]);
ret = fscanf(b->fda[ch14], "%"SCNu8" %"SCNu8, zio_alarms, drv_alarms);
if (ret != 2) {
errno = EINVAL;
return -1;
}
rewind(b->fda[ch14]);
fprintf(b->fda[ch14], "%"PRIu8" %"PRIu8, *zio_alarms, *drv_alarms);
return 0;
}
/**
* Configure an FMC Fine Delay channel to produce a pulse
* @param[in] userb device token
......@@ -83,7 +127,9 @@ int fdelay_config_pulse(struct fdelay_board *userb,
__define_board(b, userb);
struct zio_control ctrl = {0,};
uint32_t *a;
uint8_t zio_alarms = 0, drv_alarms = 0;
int fdc;
int err;
if (__fdelay_get_ch_fd(b, channel, &fdc) < 0)
return -1; /* errno already set */
......@@ -112,11 +158,15 @@ int fdelay_config_pulse(struct fdelay_board *userb,
therefore we temporarily have to check the output programming correctness in the user library. */
if (mode == FD_OUT_MODE_DELAY || mode == FD_OUT_MODE_DISABLED)
{
if(pulse->rep < 0 || pulse->rep > 16) /* delay mode allows trains of 1 to 16 pulses. */
return -EINVAL;
if(pulse->rep < 0 || pulse->rep > 16) { /* delay mode allows trains of 1 to 16 pulses. */
errno = EINVAL;
return -1;
}
if(a[FD_ATTR_OUT_START_L] == 0 && a[FD_ATTR_OUT_START_COARSE] < (600 / 8)) // 600 ns min delay
return -EINVAL;
if(a[FD_ATTR_OUT_START_L] == 0 && a[FD_ATTR_OUT_START_COARSE] < (600 / 8)) { // 600 ns min delay
errno = EINVAL;
return -1;
}
}
/* we need to fill the nsample field of the control */
......@@ -126,6 +176,21 @@ int fdelay_config_pulse(struct fdelay_board *userb,
ctrl.nbits = 32;
write(fdc, &ctrl, sizeof(ctrl));
/* The fdelay driver uses the zio trigger user. This implies that all writes
* are not queued but sent immediatly to the ZIO IO function. At that point
* an alarm could be raised. It should be save to read it immediatly.
*
* A more bullet proof solution would need a ZIO upgrade, involving a
* polling mechanism.
*/
err = fdelay_alarm_get(userb, channel, &zio_alarms, &drv_alarms);
if (err)
return err;
if (zio_alarms || drv_alarms) {
errno = FDELAY_ERR_CONFIG;
return -1;
}
return 0;
}
......
......@@ -92,14 +92,14 @@ int main(int argc, char **argv)
b = fdelay_open(dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
fdelay_strerror(errno));
exit(1);
}
if (get) {
if (fdelay_get_time(b, &t) < 0) {
fprintf(stderr, "%s: fdelay_get_time(): %s\n", argv[0],
strerror(errno));
fdelay_strerror(errno));
exit(1);
}
......@@ -111,7 +111,7 @@ int main(int argc, char **argv)
case ENOLINK: printf("link down.\n"); break;
case EAGAIN: printf("synchronization in progress.\n"); break;
case 0: printf("synchronized.\n"); break;
default: printf("error: %s\n", strerror(errno)); break;
default: printf("error: %s\n", fdelay_strerror(errno)); break;
}
printf("Time: %lli.%09li\n", (long long)t.utc, (long)t.coarse * 8);
......@@ -123,7 +123,7 @@ int main(int argc, char **argv)
if (host) {
if (fdelay_set_host_time(b) < 0) {
fprintf(stderr, "%s: fdelay_set_host_time(): %s\n",
argv[0], strerror(errno));
argv[0], fdelay_strerror(errno));
exit(1);
}
fdelay_close(b);
......@@ -144,7 +144,7 @@ int main(int argc, char **argv)
exit(1);
} else if (err) {
fprintf(stderr, "%s: fdelay_wr_mode(): %s\n",
argv[0], strerror(errno));
argv[0], fdelay_strerror(errno));
exit(1);
}
......@@ -168,7 +168,7 @@ int main(int argc, char **argv)
if (wr_off) {
if (fdelay_wr_mode(b, 0) < 0) {
fprintf(stderr, "%s: fdelay_wr_mode(): %s\n",
argv[0], strerror(errno));
argv[0], fdelay_strerror(errno));
exit(1);
}
......@@ -179,7 +179,7 @@ int main(int argc, char **argv)
if (fdelay_set_time(b, &t) < 0) {
fprintf(stderr, "%s: fdelay_set_time(): %s\n",
argv[0], strerror(errno));
argv[0], fdelay_strerror(errno));
exit(1);
}
fdelay_close(b);
......
......@@ -115,7 +115,7 @@ int input_timestamp(struct fdelay_board *b, int count, int umode, int nonblock)
if (ret < 0) {
err = ret;
fprintf(stderr, "%s: fdelay_read: %s\n", prog,
strerror(errno));
fdelay_strerror(errno));
break;
}
if (!ret)
......@@ -237,7 +237,7 @@ int main(int argc, char **argv)
b = fdelay_open(dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
fdelay_strerror(errno));
exit(1);
}
......
......@@ -351,7 +351,7 @@ int main(int argc, char **argv)
b = fdelay_open(dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
fdelay_strerror(errno));
exit(1);
}
......@@ -414,9 +414,10 @@ int main(int argc, char **argv)
goto out;
}
if ((err = fdelay_config_pulse(b, channel, &p)) < 0) {
err = fdelay_config_pulse(b, channel, &p);
if (err) {
fprintf(stderr, "%s: fdelay_config_pulse(): %s\n",
argv[0], strerror(-err));
argv[0], fdelay_strerror(errno));
exit(1);
}
while (trigger_wait) {
......@@ -429,7 +430,7 @@ int main(int argc, char **argv)
i = fdelay_has_triggered(b, channel);
if (i < 0) {
fprintf(stderr, "%s: waiting for trigger: %s\n",
argv[0], strerror(errno));
argv[0], fdelay_strerror(errno));
exit(1);
}
trigger_wait = !i;
......
......@@ -94,7 +94,7 @@ int main(int argc, char **argv)
b = fdelay_open(dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
fdelay_strerror(errno));
exit(1);
}
......@@ -112,7 +112,7 @@ int main(int argc, char **argv)
if (fdelay_get_config_pulse(b, FDELAY_OUTPUT_USER_TO_HW(ch),
&p) < 0) {
fprintf(stderr, "%s: get_config(channel %i): %s\n",
argv[0], ch, strerror(errno));
argv[0], ch, fdelay_strerror(errno));
}
/* pass hw number again, as the function is low-level */
report_output_config(FDELAY_OUTPUT_USER_TO_HW(ch),
......
......@@ -66,7 +66,7 @@ int main(int argc, char **argv)
b = fdelay_open(dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
fdelay_strerror(errno));
exit(1);
}
......@@ -85,7 +85,7 @@ int main(int argc, char **argv)
if (err)
{
fprintf(stderr, "%s: error setting termination: %s", argv[0], strerror(errno));
fprintf(stderr, "%s: error setting termination: %s", argv[0], fdelay_strerror(errno));
exit(1);
}
......
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