Commit a509cbd7 authored by Federico Vaga's avatar Federico Vaga

sw: enforce scatterlist using a module parameter

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 6bf976cb
......@@ -246,6 +246,11 @@ Module Parameters
change to this value is applied on ``open(2)``
(file ``<pci-id>/spec-<pci-id>/dma``).
``user_dma_max_segment`` [RW]
It sets the maximum size for a DMA transfer in a scatterlist. A
change to this value is applied on the next ``read(2)`` or ``write(2)``
(file ``<pci-id>/spec-<pci-id>/dma``).
DMA
---
......
......@@ -174,6 +174,30 @@ class TestDma(object):
data_rb = dma.read(offset, split)
assert data[offset:min(offset+split, buffer_size)] == data_rb
@pytest.mark.parametrize("segment_size", [2**i for i in range(3, 20)])
def test_dma_scatterlist_read(self, spec, segment_size):
"""
Enforce a scatterlist on known size to read 1MiB.
"""
buffer_size = 2**20
data = bytes([random.randrange(0, 0xFF, 1) for i in range(buffer_size)])
with spec.dma() as dma:
dma.write(0, data)
assert data == dma.read(0, len(data), segment_size)
@pytest.mark.parametrize("segment_size", [2**i for i in range(3, 12)])
def test_dma_scatterlist_write(self, spec, segment_size):
"""
Enforce a scatterlist on known size to write 1MiB.
Remember: on write the scatterlist is enforced by the driver
on buffers bigger than 4KiB
"""
buffer_size = 2**20
data = bytes([random.randrange(0, 0xFF, 1) for i in range(buffer_size)])
with spec.dma() as dma:
dma.write(0, data, segment_size)
assert data == dma.read(0, len(data))
@pytest.mark.parametrize("ddr_offset",
[0x0] + \
[2**i for i in range(int(math.log2(PySPEC.DDR_ALIGN)), int(math.log2(PySPEC.DDR_SIZE)))] + \
......
......@@ -120,30 +120,40 @@ class PySPEC:
if hasattr(self, "dma_file"):
self.dma_file.close()
def read(self, offset, size):
def read(self, offset, size, max_segment=0):
"""
Trigger a *device to memory* DMA transfer
:var offset: offset within the DDR
:var size: number of bytes to be transferred
:var max_segment: maximum size of a single transfer in a
scatterlist. Default is 0, it means to use
the DMA engine's default.
:return: the data transfered as bytes() array
:raise OSError: if the read(2) or the driver fails
"""
with open("/sys/module/spec_fmc_carrier/parameters/user_dma_max_segment", "w") as f:
f.write(str(max_segment))
self.__seek(offset)
data = []
while size - len(data) > 0:
data += self.dma_file.read(size - len(data))
return bytes(data)
def write(self, offset, data):
def write(self, offset, data, max_segment=0):
"""
Trigger a *memory to device* DMA transfer
:var offset: offset within the DDR
:var size: number of bytes to be transferred
:var max_segment: maximum size of a single transfer in a
scatterlist. Default is 0, it means to use
the DMA engine's default.
:return: the number of transfered bytes
:raise OSError: if the write(2) or the driver fails
"""
with open("/sys/module/spec_fmc_carrier/parameters/user_dma_max_segment", "w") as f:
f.write(str(max_segment))
self.__seek(offset)
start = 0
while len(data) - start > 0:
......
......@@ -29,6 +29,10 @@ static int user_dma_coherent_size = 4 * 1024 * 1024;
module_param(user_dma_coherent_size, int, 0644);
MODULE_PARM_DESC(user_dma_coherent_size,
"DMA coherent allocation's size in bytes (default 4MiB)");
static size_t user_dma_max_segment;
module_param(user_dma_max_segment, long, 0644);
MODULE_PARM_DESC(user_dma_max_segment,
"Maximum DMA segment size in bytes (default 0, meaning whatever supported by the DMA engine)");
enum spec_fpga_irq_lines {
SPEC_FPGA_IRQ_FMC_I2C = 0,
......@@ -179,6 +183,8 @@ static int spec_fpga_dbg_dma_transfer(struct spec_fpga_dbg_dma *dbgdma,
max_segment = dma_get_max_seg_size(dbgdma->dchan->device->dev);
else
max_segment = 4096;
if (user_dma_max_segment)
max_segment = min(user_dma_max_segment, max_segment);
err = sg_alloc_table(&sgt,
(count / max_segment) + !!(count % max_segment),
GFP_KERNEL);
......
......@@ -24,6 +24,8 @@ def main():
help='Minimum transfer size in Bytes (default: 4096 Bytes). It is rounded to the lower power of 2.')
parser.add_argument('--max', default=4 * 1024 * 1024, type=int,
help='Maximum transfer size in Bytes (default: 4194304 Bytes). It is rounded to the lower power of 2.')
parser.add_argument('--seg', default=0, type=int,
help='Overwrite scatterlist segment size.')
args = parser.parse_args()
tracing_path = "/sys/kernel/debug/tracing"
......@@ -41,7 +43,7 @@ def main():
with open(os.path.join(tracing_path, "trace"), "w") as f:
f.write("")
with spec.dma(size) as dma:
dma.read(0, size)
dma.read(0, size, args.seg)
with open(os.path.join(tracing_path, "trace"), "r") as f:
throughput.append((float(size) / 1024 / 1024) / dma_time_get(f.read()))
print("{:d} Bytes -> {:f} MBps".format(size, throughput[-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