Commit 4f4c7495 authored by Federico Vaga's avatar Federico Vaga

Merge branch 'pytest-improvements' into 'master'

tst: add python requirements

See merge request be-cem-edl/fec/hardware-modules/fmc-tdc-1ns-5cha!25
parents f313382e 0fc85b0f
......@@ -12,7 +12,17 @@ include:
ref: master
file:
- 'edl-gitlab-ci.yml'
- local: 'hdl/syn/.gitlab-ci.yml'
python-style:
variables:
FF_KUBERNETES_HONOR_ENTRYPOINT: 1 # Make Gitlab K8s executors to respect entrypoint in Acc-Py images, https://cern.service-now.com/service-portal?id=ticket&table=incident&n=INC3570437
stage: analyse
image:
name: gitlab-registry.cern.ch/acc-co/devops/python/distribution-images/acc-py_cc7:pro
before_script:
- pip install pycodestyle
script:
- pycodestyle --ignore=E501 pytest/ software/lib/PyFmcTdc/
cppcheck:
stage: analyse
......@@ -40,3 +50,12 @@ kernel_build_validation:
echo "Checking Dependencies"
if [ "$FMC_BUILDS" != "0" ]; then echo 'FMC did not build successfully. Exiting'; exit 1; fi
if [ "$ZIO_BUILDS" != "0" ]; then echo 'ZIO did not build successfully. Exiting'; exit 1; fi
fpga_synthesis:
extends: .synthesis-ise-14-7
interruptible: true
parallel:
matrix:
- EDL_CI_SYN_SRC_PATH:
- hdl/syn/spec
- hdl/syn/svec
# SPDX-FileCopyrightText: 2022 CERN (home.cern)
#
# SPDX-License-Identifier: LGPL-2.1-or-later
variables:
_FMC_TDC_BITSTREAM_DEST: $CI_PROJECT_DIR/$EDL_CI_EOS_OUTPUT_DIR/bitstreams
.syn_template: &syn_template
interruptible: true
stage: build
needs: []
tags:
- xilinx_ise
- "14.7"
script:
- git submodule init && git submodule update
- cd hdl/syn/"$SYN_NAME"/
- hdlmake
- make
- |
if [[ $(cat *.par | grep -c "All constraints were met") = 0 ]]
then
echo -e "\e[31mTiming errors detected in PAR report. Aborting...\e[0m"
exit 1
fi
- tar -cJf $SYN_NAME.tar.xz *.syr *.par *.twr *.bit *.bin
- mkdir -p $_FMC_TDC_BITSTREAM_DEST
- cp $SYN_NAME.tar.xz $_FMC_TDC_BITSTREAM_DEST
artifacts:
name: "$SYN_NAME-synthesis-$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
paths:
- $_FMC_TDC_BITSTREAM_DEST/*
SPEC synthesis:
variables:
SYN_NAME: "spec"
<<: *syn_template
SVEC synthesis:
variables:
SYN_NAME: "svec"
<<: *syn_template
......@@ -2,7 +2,7 @@
SPDX-License-Identifier: LGPL-2.1-or-later
SPDX-FileCopyrightText: 2020 CERN
"""
from pathlib import Path
import pytest
import subprocess
import time
......@@ -10,6 +10,48 @@ import re
import os
from PyFmcTdc import FmcTdc
def valid_slot_type(slot):
if re.search(r"(VME|PCI)\.[0-9]+-FMC\.[0-9]+", slot) is None:
raise ValueError()
return slot
def id_from_slot(slot, name):
carrier, mezzanine = slot.split("-")
carrier_bus, carrier_slot = carrier.split(".")
carrier_slot = int(carrier_slot)
mezzanine_bus, mezzanine_slot = mezzanine.split(".")
mezzanine_slot = int(mezzanine_slot)
if carrier_bus == "PCI":
with open("/run/dynpci") as f:
for line in f.readlines():
dynslot, pciid = line.strip().split(" ")
if int(dynslot) == carrier_slot:
break
pciid = f"0000:{pciid}"
pathfmc = list(Path("/sys/bus/pci/devices").joinpath(pciid)
.glob(f"spec-*/id:*/{name}.*.auto/fmc-slot-*.{mezzanine_slot}"))
elif carrier_bus == "VME":
pathfmc = list(Path("/sys/bus/vme/devices").joinpath(f"slot.{carrier_slot:02d}")
.joinpath(f"vme.{carrier_slot:02d}")
.glob(f"svec-*/svec-*/id:*/{name}.*.auto/fmc-slot-*.{mezzanine_slot}"))
else:
raise ValueError()
assert len(pathfmc) == 1
devname = list(Path(pathfmc[0]).parent.glob("hw-*/*-????/devname"))
assert len(devname) == 1
with open(devname[0]) as f:
fd_id = int(f.read().strip().split("-")[-1], 16)
return fd_id
def pytest_generate_tests(metafunc):
if "fd_tdc_id" in metafunc.fixturenames:
metafunc.parametrize("fd_tdc_id", pytest.fd_tdc_id)
class PulseGenerator(object):
def __init__(self, id):
self.id = id
......@@ -20,13 +62,14 @@ class PulseGenerator(object):
period_ns, count, sync):
pass
class SCPI(PulseGenerator):
def __init__(self, scpi_id):
super(SCPI, self).__init__(scpi_id)
import pyvisa
self.mgr = pyvisa.ResourceManager()
self.instr = self.mgr.open_resource(self.id)
self.instr.query_delay=0
self.instr.query_delay = 0
self.instr.timeout = 10000
self.instr.read_termination = '\n'
self.instr.write_termination = '\n'
......@@ -55,7 +98,7 @@ class SCPI(PulseGenerator):
# START Custom Agilent 33600A commands
self.instr.write("TRIGGER:DELAY {:d}e-6".format(rel_time_us))
burst_period_ns = int(count/(1/period_ns)) + 500
burst_period_ns = int(count / (1 / period_ns)) + 500
self.instr.write("SOURCE:BURST:INTERNAL:PERIOD {:d}ns".format(burst_period_ns))
self.instr.write("SOURCE:BURST:NCYCLES {:d}".format(count))
self.instr.write("SOURCE:BURST:STATE ON")
......@@ -67,6 +110,7 @@ class SCPI(PulseGenerator):
if sync:
self.instr.query_ascii_values("*OPC?")
class FmcFineDelay(PulseGenerator):
CHANNEL_NUMBER = 4
......@@ -74,7 +118,7 @@ class FmcFineDelay(PulseGenerator):
super(FmcFineDelay, self).__init__(fd_id)
def disable(self, ch):
cmd = ["/usr/local/bin/fmc-fdelay-pulse",
cmd = ["fmc-fdelay-pulse",
"-d", "0x{:x}".format(self.id),
"-o", str(ch),
"-m", "disable",
......@@ -84,13 +128,13 @@ class FmcFineDelay(PulseGenerator):
def generate_pulse(self, ch, rel_time_us,
period_ns, count, sync):
cmd = ["/usr/local/bin/fmc-fdelay-pulse",
cmd = ["fmc-fdelay-pulse",
"-d", "0x{:x}".format(self.id),
"-o", str(ch),
"-m", "pulse",
"-r", "{:d}u".format(rel_time_us),
"-T", "{:d}n".format(period_ns),
"-w", "{:d}n".format(int(period_ns/2)),
"-w", "{:d}n".format(int(period_ns / 2)),
"-c", str(count),
"-t"
]
......@@ -99,38 +143,51 @@ class FmcFineDelay(PulseGenerator):
if sync:
time.sleep(1 + 2 * (period_ns * count) / 1000000000.0)
@pytest.fixture(scope="module")
def fmcfd():
if pytest.fd_id is not None:
gen = FmcFineDelay(pytest.fd_id)
elif pytest.scpi is not None:
gen = SCPI(pytest.scpi)
yield gen
if isinstance(gen, FmcFineDelay):
for ch in range(FmcFineDelay.CHANNEL_NUMBER):
gen.disable(ch + 1)
elif isinstance(gen, SCPI):
gen.disable(0)
@pytest.fixture(scope="function")
def fmctdc():
tdc = FmcTdc(pytest.tdc_id)
def tdc_and_gen(fd_tdc_id):
fd_id, tdc_id = fd_tdc_id
gen = FmcFineDelay(fd_id)
for ch in range(FmcFineDelay.CHANNEL_NUMBER):
gen.disable(ch + 1)
tdc = FmcTdc(tdc_id)
for ch in tdc.chan:
ch.enable = False
ch.termination = False
ch.timestamp_mode = "post"
ch.flush()
yield (gen, tdc)
for ch in range(FmcFineDelay.CHANNEL_NUMBER):
gen.disable(ch + 1)
for ch in tdc.chan:
ch.enable = False
ch.termination = False
ch.timestamp_mode = "post"
ch.flush()
@pytest.fixture(scope="function")
def fmcfd(tdc_and_gen):
fd, tdc = tdc_and_gen
yield fd
@pytest.fixture(scope="function")
def fmctdc(tdc_and_gen):
fd, tdc = tdc_and_gen
yield tdc
def pytest_addoption(parser):
parser.addoption("--tdc-id", type=lambda x : int(x, 16),
required=True, help="Fmc TDC Linux Identifier")
parser.addoption("--fd-id", type=lambda x : int(x, 16), default=None,
help="Fmc Fine-Delay Linux Identifier")
parser.addoption("--scpi", type=str, default=None,
help="SCPI Connection String")
parser.addoption("--tdc-id", type=lambda x: int(x, 16), action="append",
default=[], help="Fmc TDC Linux Identifier")
parser.addoption("--slot-tdc", type=valid_slot_type, action='append',
default=[], help="Fmc TDC absolute slot (works only for SPEC and SVEC)")
parser.addoption("--fd-id", type=lambda x: int(x, 16), action="append",
default=[], help="Fmc Fine-Delay Linux Identifier")
parser.addoption("--slot-fd", type=valid_slot_type, action='append',
default=[], help="Fmc Fine-Delay absolute slot (works only for SPEC and SVEC)")
parser.addoption("--dump-range", type=int, default=10,
help="Timestamps to show before and after an error")
parser.addoption("--channel", type=int, default=[],
......@@ -141,33 +198,60 @@ def pytest_addoption(parser):
parser.addoption("--usr-acq-period-ns", type=int, default=0,
help="Pulses period (ns) during a acquisition test.")
def id_list_get(config, opt_id, opt_slot, devname):
id_list = config.getoption(opt_id)
if len(id_list) == 0:
slot = config.getoption(opt_slot)
if len(slot) == 0:
print(f"Missing argument {opt_id} or {opt_slot}")
raise Exception()
id_list = []
for slot in slot:
id_list.append(id_from_slot(slot, devname))
return id_list
def pytest_configure(config):
pytest.tdc_id = config.getoption("--tdc-id")
pytest.fd_id = config.getoption("--fd-id")
pytest.scpi = config.getoption("--scpi")
if pytest.scpi is None and pytest.fd_id is None:
raise Exception("You must set --fd-id or --scpi")
pytest.tdc_id = id_list_get(config, "--tdc-id", "--slot-tdc", "fmc-tdc")
pytest.fd_id = id_list_get(config, "--fd-id", "--slot-fd", "fmc-fdelay-tdc")
if len(pytest.tdc_id) != len(pytest.fd_id):
print("For each --fd-id there must be a --tdc-id")
raise Exception()
pytest.fd_tdc_id = list(zip(pytest.fd_id, pytest.tdc_id))
pytest.channels = config.getoption("--channel")
if len(pytest.channels) == 0:
pytest.channels = range(FmcTdc.CHANNEL_NUMBER)
if len(pytest.channels) != 1 and pytest.scpi is not None:
raise Exception("With --scpi we can test only the channel connected to the Waveform generator. Set --channel")
pytest.usr_acq = (config.getoption("--usr-acq-period-ns"),
config.getoption("--usr-acq-count"))
pytest.dump_range = config.getoption("--dump-range")
pytest.transfer_mode = None
with open("/sys/bus/zio/devices/tdc-1n5c-{:04x}/transfer-mode".format(pytest.tdc_id)) as f_mode:
mode = int(f_mode.read().rstrip())
for k, v in FmcTdc.TRANSFER_MODE.items():
if mode == v:
pytest.transfer_mode = k
modes = []
for tdc_id in pytest.tdc_id:
with open(f"/sys/bus/zio/devices/tdc-1n5c-{tdc_id:04x}/transfer-mode") as f_mode:
modes.append(int(f_mode.read().rstrip()))
mode = set(modes)
if len(mode) != 1:
print("Inconsistent transfer mode across devices")
raise Exception()
for k, v in FmcTdc.TRANSFER_MODE.items():
if v in mode:
pytest.transfer_mode = k
pytest.carrier = None
full_path = os.readlink("/sys/bus/zio/devices/tdc-1n5c-{:04x}".format(pytest.tdc_id))
for carr in ["spec", "svec"]:
is_carr = re.search(carr, full_path)
if is_carr is not None:
carrs = []
for tdc_id in pytest.tdc_id:
full_path = os.readlink("/sys/bus/zio/devices/tdc-1n5c-{:04x}".format(tdc_id))
for carr in ["spec", "svec"]:
is_carr = re.search(carr, full_path)
if is_carr is None:
continue
if pytest.carrier is not None and pytest.carrier != carr:
print("Inconsistent installation mix of SPEC and SVEC")
raise Exception()
pytest.carrier = carr
# SPDX-FileCopyrightText: 2023 CERN (home.cern)
#
# SPDX-License-Identifier: LGPL-2.1-or-later
pytest
......@@ -7,6 +7,7 @@ import pytest
import random
from PyFmcTdc import FmcTdc
class TestFmctdcGetterSetter(object):
@pytest.mark.parametrize("i", range(FmcTdc.CHANNEL_NUMBER))
......@@ -16,7 +17,6 @@ class TestFmctdcGetterSetter(object):
fmctdc.chan[i].termination = term
assert term == fmctdc.chan[i].termination
@pytest.mark.parametrize("i", range(FmcTdc.CHANNEL_NUMBER))
@pytest.mark.parametrize("term", [True, False])
def test_termination(self, fmctdc, i, term):
......@@ -53,7 +53,7 @@ class TestFmctdcGetterSetter(object):
assert fmctdc.chan[i].enable == (i == ch)
fmctdc.chan[ch].enable = False
for i in range(FmcTdc.CHANNEL_NUMBER):
assert fmctdc.chan[i].enable == False
assert fmctdc.chan[i].enable is False
@pytest.mark.parametrize("i", range(FmcTdc.CHANNEL_NUMBER))
@pytest.mark.parametrize("buffer_mode", FmcTdc.FmcTdcChannel.BUFFER_MODE.keys())
......
......@@ -4,19 +4,19 @@ SPDX-FileCopyrightText: 2020 CERN
"""
import pytest
import random
import select
import time
import sys
import os
from PyFmcTdc import FmcTdc, FmcTdcTime
TDC_FD_CABLING = [1, 2, 3, 4, 4]
fmctdc_acq_100ns_spec = [(200, 65000), # 5 MHz
(250, 65000), # 4 MHz
(500, 65000), # 2 MHz
(1000, 65000), # 1 Mhz
fmctdc_acq_100ns_spec = [(200, 65000), # 5 MHz
(250, 65000), # 4 MHz
(500, 65000), # 2 MHz
(1000, 65000), # 1 Mhz
(1700, 65000), # 588 kHz
# Let's keep the test within 100ms duration
# vvvvvvvvvvv
......@@ -24,23 +24,26 @@ fmctdc_acq_100ns_spec = [(200, 65000), # 5 MHz
(2500, 40000), # 400 kHz
(5000, 20000), # 200 khz
(10000, 10000), # 100 kHz
(12500, 8000), # 80 kHz
(20000, 5000), # 50 kHz
(100000, 1000), # 10 kHz
(1000000, 100), # 1 kHz
(12500, 8000), # 80 kHz
(20000, 5000), # 50 kHz
(100000, 1000), # 10 kHz
(1000000, 100), # 1 kHz
(10000000, 10)] # 100 Hz
fmctdc_acq_100ns_svec = [(13333, 8000), # 75 kHz
(20000, 5000), # 50 kHz
(100000, 1000), # 10 kHz
(1000000, 100), # 1 kHz
(10000000, 10)] # 100 Hz
fmctdc_acq_100ns_svec = [(13333, 8000), # 75 kHz
(20000, 5000), # 50 kHz
(100000, 1000), # 10 kHz
(1000000, 100), # 1 kHz
(10000000, 10)] # 100 Hz
fmctdc_acq_100ns = fmctdc_acq_100ns_svec if pytest.transfer_mode == "fifo" else fmctdc_acq_100ns_spec
@pytest.fixture(scope="function", params=pytest.channels)
def fmctdc_chan(request):
tdc = FmcTdc(pytest.tdc_id)
def fmctdc_chan(request, fmctdc):
tdc = fmctdc
for ch in tdc.chan:
ch.enable = False
tdc.chan[request.param].termination = False
......@@ -54,6 +57,7 @@ def fmctdc_chan(request):
tdc.chan[request.param].enable = False
del tdc
class TestFmctdcAcquisition(object):
def test_acq_single_channel_disable(self, fmctdc_chan, fmcfd):
......@@ -69,14 +73,13 @@ class TestFmctdcAcquisition(object):
correctly. Test 100 milli-second acquisition at different
frequencies"""
stats_before = fmctdc_chan.stats
fmctdc_chan.buffer_len = max(count + 1, 64)
fmctdc_chan.buffer_len = max(count + 1, 64)
fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000,
period_ns, count, True)
stats_after = fmctdc_chan.stats
assert stats_before[0] + count == stats_after[0]
@pytest.mark.skipif(pytest.carrier != "spec" or \
pytest.transfer_mode != "dma",
@pytest.mark.skipif(pytest.carrier != "spec" or pytest.transfer_mode != "dma",
reason="Only SPEC with DMA can perform this test")
@pytest.mark.parametrize("period_ns", [200, 250, 500, 1000])
@pytest.mark.repeat(100)
......@@ -86,7 +89,7 @@ class TestFmctdcAcquisition(object):
if we missed a timestamp or not. this is a fine-delay limitation"""
count = 0xFFFF
stats_before = fmctdc_chan.stats
fmctdc_chan.buffer_len = count + 1
fmctdc_chan.buffer_len = count + 1
fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000,
period_ns, count, True)
stats_after = fmctdc_chan.stats
......@@ -98,32 +101,30 @@ class TestFmctdcAcquisition(object):
metadata is valid. Coars and franc within range, and the sequence
number increases by 1 Test 100 milli-second acquisition at different
frequencies"""
fmctdc_chan.buffer_len = max(count + 1, 64)
fmctdc_chan.buffer_len = max(count + 1, 64)
prev = None
fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000,
period_ns, count, True)
ts = fmctdc_chan.read(count, os.O_NONBLOCK)
assert len(ts) == count
for i in range(len(ts)):
for i in range(len(ts)):
assert 0 <= ts[i].coarse < 125000000
assert 0 <= ts[i].frac < 4096
if prev == None:
if prev is None:
prev = ts[i]
continue
assert ts[i].seq_id == (prev.seq_id + 1) & 0xFFFFFFF, \
"Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1,
i,
len(ts),
str(prev),
str(ts[i]),
"\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) -1)]]))
"Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1,
i,
len(ts),
str(prev),
str(ts[i]),
"\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) - 1)]]))
prev = ts[i]
@pytest.mark.skipif(0 in pytest.usr_acq,
reason="Missing user acquisition option")
@pytest.mark.skipif(pytest.carrier == "spec" and \
pytest.transfer_mode == "fifo" and \
pytest.usr_acq[0] < 7000,
@pytest.mark.skipif(pytest.carrier == "spec" and pytest.transfer_mode == "fifo" and pytest.usr_acq[0] < 7000,
reason="On SPEC with FIFO acquisition we can't do more than 100kHz")
@pytest.mark.parametrize("period_ns,count", [pytest.usr_acq])
def test_acq_timestamp_single_channel(self, capsys, fmctdc_chan, fmcfd,
......@@ -141,7 +142,7 @@ class TestFmctdcAcquisition(object):
pending = count
prev = None
# be able to buffer for 1 second
fmctdc_chan.buffer_len = int(1/(period_ns/1000000000.0)) + 1
fmctdc_chan.buffer_len = int(1 / (period_ns / 1000000000.0)) + 1
stats_o = fmctdc_chan.stats
trans_b = stats_o[1]
fmcfd.generate_pulse(TDC_FD_CABLING[fmctdc_chan.idx], 1000,
......@@ -157,16 +158,16 @@ class TestFmctdcAcquisition(object):
ts = fmctdc_chan.read(1000, os.O_NONBLOCK)
assert len(ts) <= 1000
for i in range(len(ts)):
if prev == None:
if prev is None:
prev = ts[i]
continue
assert ts[i].seq_id == (prev.seq_id + 1) & 0xFFFFFFF, \
"Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1,
i,
len(ts),
str(prev),
str(ts[i]),
"\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) -1)]]))
"Missed {:d} timestamps (idx: {:d}, max: {:d}, prev: {{ {:s}, curr: {:s} }}, full dump;\n{:s}".format(ts[i].seq_id - prev.seq_id + 1,
i,
len(ts),
str(prev),
str(ts[i]),
"\n".join([str(x) for x in ts[max(0, i - pytest.dump_range):min(i + pytest.dump_range, len(ts) - 1)]]))
prev = ts[i]
pending -= len(ts)
poll.unregister(fmctdc_chan.fileno)
......
......@@ -5,6 +5,7 @@ SPDX-FileCopyrightText: 2020 CERN
import pytest
class TestFmctdcTemperature(object):
def test_temperature_read(self, fmctdc):
......
......@@ -8,14 +8,15 @@ import random
import time
from PyFmcTdc import FmcTdcTime
class TestFmctdcTime(object):
def test_whiterabbit_mode(self, fmctdc):
"""It must be possible to toggle the White-Rabbit status"""
fmctdc.whiterabbit_mode = True
assert fmctdc.whiterabbit_mode == True
assert fmctdc.whiterabbit_mode is True
fmctdc.whiterabbit_mode = False
assert fmctdc.whiterabbit_mode == False
assert fmctdc.whiterabbit_mode is False
def test_time_set_fail_wr(self, fmctdc):
"""Time can't be changed when White-Rabbit is enabled"""
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ACAM TDC-GPX routines support for fmc-tdc driver.
*
* Copyright (C) 2013 CERN (http://www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/kernel.h>
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* EEPROM calibration block retreival code for fmc-tdc.
*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Tomasz Włostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/moduleparam.h>
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* fmc-tdc (a.k.a) FmcTdc1ns5cha main header.
*
......@@ -5,8 +6,6 @@
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/kernel.h>
#include <linux/init.h>
......@@ -286,63 +285,60 @@ static int ft_zio_block_nr_pages(struct zio_block *block)
}
static int sg_alloc_table_from_block(struct device *dev,
struct sg_table *sgt,
struct zio_block *block)
struct sg_table *sgt,
struct zio_block *block)
{
struct page **pages;
unsigned int nr_pages;
size_t max_segment_size;
void *data;
int i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
int err;
#else
struct scatterlist *sg;
struct page **pages;
unsigned int nr_pages;
size_t max_segment_size;
void *data;
int i;
int err = 0;
#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE
struct scatterlist *sg;
#endif
if (!block)
return -EINVAL;
nr_pages = ft_zio_block_nr_pages(block);
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
if (!pages)
return -ENOMEM;
data = (void *) block->data;
if (is_vmalloc_addr(data)) {
for (i = 0; i < nr_pages; ++i) {
pages[i] = vmalloc_to_page(data + PAGE_SIZE * i);
}
} else {
for (i = 0; i < nr_pages; ++i)
pages[i] = virt_to_page(data + PAGE_SIZE * i);
}
max_segment_size = dma_get_max_seg_size(dev);
max_segment_size &= PAGE_MASK; /* to make alloc_table happy */
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
err = __sg_alloc_table_from_pages(sgt, pages, nr_pages,
if (!block)
return -EINVAL;
nr_pages = ft_zio_block_nr_pages(block);
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
if (!pages)
return -ENOMEM;
data = (void *) block->data;
if (is_vmalloc_addr(data)) {
for (i = 0; i < nr_pages; ++i)
pages[i] = vmalloc_to_page(data + PAGE_SIZE * i);
} else {
for (i = 0; i < nr_pages; ++i)
pages[i] = virt_to_page(data + PAGE_SIZE * i);
}
max_segment_size = dma_get_max_seg_size(dev);
max_segment_size &= PAGE_MASK; /* to make alloc_table happy */
#if KERNEL_VERSION(5, 9, 0) > LINUX_VERSION_CODE
err = __sg_alloc_table_from_pages(sgt, pages, nr_pages,
offset_in_page(data),
block->datalen,
max_segment_size,
GFP_KERNEL);
if (err)
sg_free_table(sgt);
kfree(pages);
return err;
#else
sg = __sg_alloc_table_from_pages(sgt, pages, nr_pages,
sg = __sg_alloc_table_from_pages(sgt, pages, nr_pages,
offset_in_page(data),
block->datalen,
max_segment_size,
NULL,
0,
GFP_KERNEL);
if (IS_ERR(sg))
sg_free_table(sgt);
kfree(pages);
return PTR_ERR(sg);
if (IS_ERR(sg))
err = PTR_ERR(sg);
#endif
if (err)
sg_free_table(sgt);
kfree(pages);
return err;
}
static int ft_zio_block_dma_map_sg(struct fmctdc_dev *ft, unsigned int ch,
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Main fmc-tdc driver module.
*
* Copyright (C) 2012-2013 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/kernel.h>
......@@ -34,7 +33,7 @@ int irq_timeout_ms_default = 10;
module_param_named(irq_timeout_ms, irq_timeout_ms_default, int, 0444);
MODULE_PARM_DESC(irq_timeout_ms, "IRQ coalesing timeout (default: 10ms).");
static int test_data_period = 0;
static int test_data_period;
module_param_named(test_data_period, test_data_period, int, 0444);
MODULE_PARM_DESC(test_data_period,
"It sets how many fake timestamps to generate every seconds on the first channel, 0 to disable (default: 0)");
......@@ -209,6 +208,7 @@ static int ft_channels_init(struct fmctdc_dev *ft)
for (i = FT_CH_1; i <= FT_NUM_CHANNELS; i++) {
int ret = ft_init_channel(ft, i);
if (ret < 0)
return ret;
/* termination is off by default */
......@@ -450,7 +450,7 @@ int ft_probe(struct platform_device *pdev)
}
}
if(!ft_fmc_slot_is_valid(ft))
if (!ft_fmc_slot_is_valid(ft))
goto out_fmc_err;
err = sysfs_create_link(&ft->pdev->dev.kobj, &ft->slot->dev.kobj,
......@@ -461,7 +461,7 @@ int ft_probe(struct platform_device *pdev)
goto err_fmc_link;
}
ret = ft_calib_init(ft);
ret = ft_calib_init(ft);
if (ret < 0)
goto err_calib;
......@@ -492,9 +492,9 @@ int ft_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ft);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE
ret = ft_hwmon_init(ft);
if(ret != 0)
if (ret != 0)
dev_err(dev, "Could not create HWMON device: %d", ret);
#endif
......@@ -546,6 +546,7 @@ int ft_remove(struct platform_device *pdev)
i = ARRAY_SIZE(init_subsystems);
while (--i >= 0) {
struct ft_modlist *m = init_subsystems + i;
if (m->exit)
m->exit(ft);
}
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* fmc-tdc (a.k.a) FmcTdc1ns5cha main header.
*
......@@ -5,8 +6,6 @@
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/kernel.h>
#include <linux/init.h>
......@@ -147,7 +146,7 @@ static irqreturn_t ft_irq_handler_ts_fifo(int irq, void *dev_id)
redo--;
}
}
} while(irq_stat && redo);
} while (irq_stat && redo);
ft_iowrite(ft, irq_stat_orig, ft->ft_irq_base + TDC_EIC_REG_EIC_ISR);
return IRQ_HANDLED;
......
......@@ -10,7 +10,7 @@
#include <linux/hwmon.h>
#include "fmc-tdc.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)
#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE
static umode_t ft_hwmon_temp_is_visible(const void *_data,
enum hwmon_sensor_types type, u32 attr,
......@@ -25,23 +25,23 @@ static int ft_hwmon_temp_read(struct device *dev, enum hwmon_sensor_types type,
int value, ret;
struct fmctdc_dev *ft = dev_get_drvdata(dev);
switch(attr) {
case hwmon_temp_min:
*val = -25*1000;
return 0;
switch (attr) {
case hwmon_temp_min:
*val = -25*1000;
return 0;
case hwmon_temp_max:
*val = 60*1000;
return 0;
case hwmon_temp_max:
*val = 60*1000;
return 0;
case hwmon_temp_crit:
*val = 65*1000;
return 0;
case hwmon_temp_crit:
*val = 65*1000;
return 0;
}
ret = ft_temperature_get(ft, &value);
if(ret < 0) {
if (ret < 0) {
dev_err(dev, "Could not read temperature: %d", ret);
return ret;
}
......@@ -88,12 +88,12 @@ int ft_hwmon_init(struct fmctdc_dev *ft)
ft,
&ft_hwmon_temp_chip_info,
NULL);
if(!IS_ERR(ft->hwmon_dev)) {
if (!IS_ERR(ft->hwmon_dev)) {
ft->hwmon_temp_sensor_id = devm_kasprintf(ft->hwmon_dev,
GFP_KERNEL,
"Temperature [%s]",
dev_name(&ft->slot->dev));
if(!ft->hwmon_temp_sensor_id) {
if (!ft->hwmon_temp_sensor_id) {
devm_hwmon_device_unregister(dev);
return -ENOMEM;
}
......
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2023 CERN (home.cern)
/*
* Time-related routines for fmc-tdc driver.
*
* Copyright (C) 2013 CERN (http://www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/kernel.h>
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ZIO interface for the fmc-tdc driver.
*
* Copyright (C) 2012-2013 CERN (www.cern.ch)
* Author: Tomasz Włostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <linux/kernel.h>
......@@ -138,10 +137,10 @@ int ft_temperature_get(struct fmctdc_dev *ft, int *temp)
static int ft_unique_id_get(struct fmctdc_dev *ft, uint64_t *id)
{
int stat = ft_ioread( ft, ft->ft_owregs_base + TDC_OW_REG_CSR);
int stat = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_CSR);
uint32_t tmp_l, tmp_h;
if( !( stat & TDC_OW_CSR_VALID ) )
if (!(stat & TDC_OW_CSR_VALID))
return -EIO;
tmp_l = ft_ioread(ft, ft->ft_owregs_base + TDC_OW_REG_ID_L);
......@@ -487,10 +486,10 @@ static struct zio_driver ft_zdrv = {
.probe = ft_zio_probe,
.remove = ft_zio_remove,
/* Take the version from ZIO git sub-module */
/* Change it if you use new features from a specific patch */
.min_version = ZIO_VERSION(__ZIO_MIN_MAJOR_VERSION,
__ZIO_MIN_MINOR_VERSION,
0), /* Change it if you use new features from
a specific patch */
0),
};
#define FT_TRIG_POST_DEFAULT 1
......@@ -590,11 +589,11 @@ static int ft_trig_data_done(struct zio_cset *cset)
goto out;
ts = cset->chan->active_block->data;
for(i = 0; i < cset->ti->nsamples; ++i) {
for (i = 0; i < cset->ti->nsamples; ++i) {
dev_dbg(&cset->head.dev,
"%s TS = {ts-num: %d, ts-num-max: %d, sec: 0x%x, coarse: 0x%x frac: 0x%x, meta: 0x%x}\n",
__func__, i, cset->ti->nsamples,
ts[i].seconds,ts[i].coarse,
ts[i].seconds, ts[i].coarse,
ts[i].frac, ts[i].metadata);
}
ft_zio_update_ctrl(cset, &ts[0]);
......@@ -678,7 +677,7 @@ int ft_zio_init(struct fmctdc_dev *ft)
if (err)
goto err_dev_reg;
for(i = 0; i < FT_NUM_CHANNELS; i++) {
for (i = 0; i < FT_NUM_CHANNELS; i++) {
ft_raw_mode_set(ft, i, 0);
ft_update_offsets(ft, i);
}
......
......@@ -6,20 +6,19 @@ SPDX-License-Identifier: LGPL-2.1-or-later
SPDX-FileCopyrightText: 2020 CERN (home.cern)
"""
import threading
import ctypes
import errno
import time
import os
class FmcTdcTime(ctypes.Structure):
_fields_ = [
("seconds", ctypes.c_uint64),
("coarse", ctypes.c_uint32),
("frac", ctypes.c_uint32),
("seq_id", ctypes.c_uint32),
("debug", ctypes.c_uint32),
]
("seconds", ctypes.c_uint64),
("coarse", ctypes.c_uint32),
("frac", ctypes.c_uint32),
("seq_id", ctypes.c_uint32),
("debug", ctypes.c_uint32),
]
def __str__(self):
return "seq: {:d} timestamp: {:f} raw: {:08x}:{:08x}:{:08x}, debug: {:08x}".format(self.seq_id, float(self), self.seconds, self.coarse, self.frac, self.debug)
......@@ -31,7 +30,6 @@ class FmcTdcTime(ctypes.Structure):
return ts
def libfmctdc_create():
"""
Initialize the libfmctdc C library
......@@ -102,12 +100,12 @@ def libfmctdc_create():
libfmctdc.fmctdc_get_time.restype = ctypes.c_int
libfmctdc.fmctdc_get_time.errcheck = error_check_int
libfmctdc.fmctdc_wr_mode.argtypes =[ctypes.c_void_p,
ctypes.c_int]
libfmctdc.fmctdc_wr_mode.argtypes = [ctypes.c_void_p,
ctypes.c_int]
libfmctdc.fmctdc_wr_mode.restype = ctypes.c_int
libfmctdc.fmctdc_wr_mode.errcheck = error_check_int
libfmctdc.fmctdc_check_wr_mode.argtypes =[ctypes.c_void_p]
libfmctdc.fmctdc_check_wr_mode.argtypes = [ctypes.c_void_p]
libfmctdc.fmctdc_check_wr_mode.restype = ctypes.c_int
# Channel
......@@ -230,8 +228,10 @@ def libfmctdc_create():
return libfmctdc
libfmctdc = libfmctdc_create()
def fmctdc_strerror(err):
"""
Return FMC-TDC errors
......@@ -241,6 +241,7 @@ def fmctdc_strerror(err):
"""
return libfmctdc.fmctdc_strerror(err)
class FmcTdc(object):
"""
It is a Python class that represent an FMC TDC device
......@@ -361,12 +362,12 @@ class FmcTdc(object):
def read(self, n=1, flags=0):
ts = (FmcTdcTime * n)()
ret = libfmctdc.fmctdc_read(self.tkn, self.idx, ts ,n ,flags)
ret = libfmctdc.fmctdc_read(self.tkn, self.idx, ts, n, flags)
return list(ts)[:ret]
def fread(self, n=1, flags=0):
ts = (FmcTdcTime * n)()
libfmctdc.fmctdc_fread(self.tkn, self.idx, ts, n ,flags)
libfmctdc.fmctdc_fread(self.tkn, self.idx, ts, n, flags)
return list(ts)
def flush(self):
......
......@@ -17,4 +17,4 @@ setup(name='PyFmcTdc',
url='http://www.ohwr.org/projects/fmc-tdc',
packages=['PyFmcTdc'],
license='LGPL-2.1-or-later',
)
)
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