Commit 608454f4 authored by Dimitris Lampridis's avatar Dimitris Lampridis

Merge branch '34-conflict-between-multiple-sync-users-on-same-hmq' into 'master'

Resolve "Conflict between multiple sync users on same HMQ"

Closes #34

See merge request be-cem-edl/common/mockturtle!25
parents b14d6642 e2c71417
......@@ -49,7 +49,7 @@ trtl-project-creator:
interruptible: true
stage: build
script:
- yum install -y bison flex python python-jinja2
- yum install -y gcc bison flex python python-jinja2
- $PWD/software/tools/trtl-project-creator/trtl-project-creator -d /tmp/ -s trtl_tst -l trtl_project_test
- TRTL=$PWD make -C /tmp/trtl_project_test/software lib
- TRTL=$PWD make -C /tmp/trtl_project_test/software tools
......
......@@ -321,12 +321,7 @@ static inline int rt_action_run(enum trtl_mq_type type,
msg_out.header->flags = TRTL_HMQ_HEADER_FLAG_ACK;
msg_out.header->msg_id = 0;
msg_out.header->len = 0;
/*
* Every combination of CPU+HMQ has a unique sync_id. We avoid copying
* the sync_id from the incoming message and prefer rebuilding it in the
* firmware in order to detect possible wrong deliveries of sync messages.
*/
msg_out.header->sync_id = ((idx_mq << 8) | trtl_get_core_id()) & 0xffff;
msg_out.header->sync_id = msg->header->sync_id;
err = action(msg, &msg_out);
if (err)
......
......@@ -38,14 +38,22 @@
static DEFINE_IDA(trtl_ida);
#if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE
static int trtl_dev_uevent(const struct device *dev, struct kobj_uevent_env *env)
#else
static int trtl_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
#endif
{
add_uevent_var(env, "DEVMODE=%#o", 0660);
return 0;
}
#if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE
static char *trtl_devnode(const struct device *dev, umode_t *mode)
#else
static char *trtl_devnode(struct device *dev, umode_t *mode)
#endif
{
return kasprintf(GFP_KERNEL, "mockturtle/%s", dev_name(dev));
}
......
......@@ -193,12 +193,14 @@ struct trtl_hmq {
* Describe the consumer of the output slot
* @list: to keep it in our local queue
* @hmq: reference to opened HMQ
* @lock: to protect flags, wait_id
* @lock: to protect flags
* @flags: status flags for syncrhonous messages
* @idx_r: index read pointer for the message circular buffer. This is
* protected by the input buffer lock. Accessing this field means that
* you are accessing the buffer input, and in order to do that you need
* to get the input buffer spinlock. So, we are protecting this
* variable as well.
* @sync_id: Unique sync id to be used when waiting for sync answer
*/
struct trtl_hmq_user {
struct list_head list;
......@@ -206,7 +208,7 @@ struct trtl_hmq_user {
spinlock_t lock;
unsigned long flags;
unsigned int idx_r;
uint16_t wait_id;
uint16_t sync_id;
};
......
......@@ -18,6 +18,7 @@
#include <linux/circ_buf.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#include <linux/idr.h>
#include <mockturtle/hw/mockturtle_queue.h>
#include <mockturtle/hw/mockturtle_cpu_csr.h>
......@@ -44,7 +45,7 @@ static bool trtl_msg_is_ack(struct trtl_msg *msg)
static bool trtl_hmq_user_msg_is_answer(struct trtl_hmq_user *user,
struct trtl_msg *msg)
{
return (user->wait_id == msg->hdr.sync_id);
return (user->sync_id == msg->hdr.sync_id);
}
/**
......@@ -54,12 +55,10 @@ static bool trtl_hmq_user_msg_is_answer(struct trtl_hmq_user *user,
*
* Return: 0 on success otherwise a negative error number
*/
static void trtl_hmq_user_sync_wait_set(struct trtl_hmq_user *user,
uint16_t id)
static void trtl_hmq_user_sync_wait_set(struct trtl_hmq_user *user)
{
spin_lock(&user->lock);
user->flags |= TRTL_HMQ_USER_FLAG_SYNC_WAIT;
user->wait_id = id;
spin_unlock(&user->lock);
}
......@@ -528,6 +527,8 @@ static unsigned int trtl_hmq_buf_idx_get(struct mturtle_hmq_buffer *buf,
return idx_r_absolute & (buf->entries - 1);
}
static DEFINE_IDA(trtl_hmq_user_ida);
/**
* It simply opens a HMQ device
*/
......@@ -536,6 +537,7 @@ static int trtl_hmq_open(struct inode *inode, struct file *file)
struct trtl_hmq_user *user;
struct trtl_hmq *hmq;
int m = iminor(inode);
int id;
unsigned long flags;
hmq = to_trtl_hmq(minors[m]);
......@@ -553,6 +555,12 @@ static int trtl_hmq_open(struct inode *inode, struct file *file)
hmq->n_user++;
spin_unlock_irqrestore(&hmq->lock, flags);
/* Assign new unique 16-bit sync_id to this user */
id = ida_simple_get(&trtl_hmq_user_ida, 0, 65536, GFP_KERNEL);
if (id < 0)
return id;
user->sync_id = id;
spin_lock_irqsave(&hmq->buf_in.lock, flags);
/* Point to the current position in buffer */
user->idx_r = hmq->buf_in.idx_w;
......@@ -573,6 +581,7 @@ static int trtl_hmq_release(struct inode *inode, struct file *f)
/* Remove user from the list */
spin_lock_irqsave(&hmq->lock, flags);
hmq->n_user--;
ida_simple_remove(&trtl_hmq_user_ida, user->sync_id);
list_del(&user->list);
kfree(user);
spin_unlock_irqrestore(&hmq->lock, flags);
......@@ -591,7 +600,6 @@ static int trtl_hmq_write_one(struct trtl_hmq_user *user,
const char __user *ubuf)
{
struct trtl_hmq *hmq = user->hmq;
struct trtl_cpu *cpu = to_trtl_cpu(hmq->dev.parent);
struct trtl_msg *msg;
int err = 0, copy_size;
size_t size;
......@@ -617,12 +625,9 @@ static int trtl_hmq_write_one(struct trtl_hmq_user *user,
}
if (trtl_hmq_user_is_sync(user)) {
/* Every combination of CPU+HMQ has a unique sync_id */
uint16_t sync_id = ((hmq->index << 8) | cpu->index) & 0xFFFF;
buf->msg_tmp.hdr.flags |= TRTL_HMQ_HEADER_FLAG_SYNC;
buf->msg_tmp.hdr.sync_id = sync_id;
trtl_hmq_user_sync_wait_set(user, sync_id);
buf->msg_tmp.hdr.sync_id = user->sync_id;
trtl_hmq_user_sync_wait_set(user);
}
/* don't sleep here */
......
......@@ -92,12 +92,6 @@ def trtl_version_exp():
return v
# @pytest.fixture(scope="module")
# def trtl_hmq():
# dev = PyMockTurtle.TrtlDevice(devid()) for cpu in dev.cpu:
# for hmq in cpu.hmq:
# yield hmq
def pytest_addoption(parser):
parser.addoption("--id", type=lambda x: int(x, 0),
required=True, help="Mockturtle identifier")
......
......@@ -32,10 +32,8 @@ def trtl_binary_hmq_sync(trtl_firmware_dir):
"firmware/hmq-sync/fw-hmq-sync.bin")
def do_sync_mult(q, hmq_orig, msg):
def do_sync_mult(q, hmq, msg):
try:
dev = PyMockTurtle.TrtlDevice(hmq_orig.trtl_dev.device_id)
hmq = dev.cpu[hmq_orig.idx_cpu].hmq[hmq_orig.idx_hmq]
q.put(hmq.sync_msg(msg))
except Exception as e:
print(e)
......@@ -143,26 +141,6 @@ class TestHmq(object):
break
assert i == val
def __do_sync_msg(self, hmq, trtl_msg):
msg_r_a = []
# I do not understand why I can't make Pool() working.
# it complains about hmq
# with multiprocessing.Pool(processes=len(trtl_msg)) as p:
# msg_r_a = p.starmap(do_sync_msg,
# [(hmq, msg) for msg in trtl_msg])
proc = []
for msg in trtl_msg:
q = multiprocessing.Queue()
proc.append((q, multiprocessing.Process(target=do_sync_msg,
args=(q, hmq, msg))))
for q, p in proc:
p.start()
for q, p in proc:
msg_r_a.append(q.get())
p.join()
return msg_r_a
@pytest.mark.parametrize("nproc", range(1, 5))
def test_sync_no_multone(self, trtl_cpu, nproc):
"""The driver should not accept more than 1 sync message at time
......@@ -192,14 +170,19 @@ class TestHmq(object):
trtl_cpu.load_application_file(trtl_binary_hmq_sync)
trtl_cpu.enable()
for hmq in trtl_cpu.hmq:
for hmq_orig in trtl_cpu.hmq:
proc = []
sb = hmq.get_stats()
sb = hmq_orig.get_stats()
for msg in trtl_msg:
# Create separate handle/user for each process
dev = PyMockTurtle.TrtlDevice(hmq_orig.trtl_dev.device_id)
hmq = dev.cpu[hmq_orig.idx_cpu].hmq[hmq_orig.idx_hmq]
q = multiprocessing.Queue()
p = multiprocessing.Process(target=do_sync_mult,
args=(q, hmq, msg))
proc.append((q, p, msg))
# Only start once all handles are open
for q, p, msg in proc:
p.start()
for q, p, msg in proc:
msg_r = q.get()
......@@ -212,7 +195,7 @@ class TestHmq(object):
assert msg_r.header.flags == PyMockTurtle.TrtlHmqHeader.TRTL_HMQ_HEADER_FLAG_ACK
for v1, v2 in zip(msg.payload, msg_r.payload):
assert v1 == v2
sa = hmq.get_stats()
sa = hmq_orig.get_stats()
assert sa["message_sent"] - sb["message_sent"] == len(trtl_msg)
assert sa["message_received"] - sb["message_received"] == len(trtl_msg)
......
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