Commit fc282bb9 authored by Federico Vaga's avatar Federico Vaga

wrtd:rt:out: improve trigger assignement by returing back to a hash table

Now the hash table is simpler than before. Most of the work is done in
user space
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>


NOTE
This commit has been created by `git subtree` on the Mock Turtle repository
on tag mock-turtle-2.0

This commit will not compile
parent a6526326
......@@ -106,7 +106,9 @@ enum wrtd_in_actions {
enum wrtd_out_actions {
WRTD_OUT_ACTION_SW_TRIG = __RT_ACTION_RECV_STANDARD_NUMBER,
WRTD_OUT_ACTION_TRIG_IDX,
WRTD_OUT_ACTION_TRIG_ORD,
WRTD_OUT_ACTION_TRIG_FRE,
WRTD_OUT_ACTION_TRIG_ADD,
WRTD_OUT_ACTION_TRIG_DEL,
WRTD_OUT_ACTION_LOG,
};
......@@ -475,4 +477,18 @@ struct wrtd_out {
struct wrtd_trigger_entry last_received;
};
/**
* Hash function, returing the hash table index corresponding to a given
* trigger ID
*/
static inline int wrtd_hash_func(struct wrtd_trig_id *id)
{
int h = 0;
h += id->system * 10291;
h += id->source_port * 10017;
h += id->trigger * 3111;
return h & (FD_HASH_ENTRIES - 1); // hash table size must be a power of 2
}
#endif
......@@ -104,19 +104,22 @@ static int wrtd_out_trigger_index_get(struct wrtd_desc *wrtd,
errno = EWRTD_NOFOUND_TRIGGER;
return -1;
}
if (hdr.msg_id != WRTD_OUT_ACTION_TRIG_IDX &&
hdr.msg_id != WRTD_OUT_ACTION_TRIG_FRE) {
errno = EWRNC_INVALID_MESSAGE;
return -1;
}
/* return the trigger index */
return msg.data[sizeof(struct wrnc_proto_header) / 4];
}
/**
* It retrieves the trigger index for the given trigger ID
*/
static int wrtd_out_trigger_order(struct wrtd_desc *wrtd, uint32_t tid)
static inline int wrtd_out_trigger_hash(struct wrtd_desc *wrtd, uint32_t tid,
uint8_t msgid)
{
struct wrnc_proto_header hdr = {
.msg_id = WRTD_OUT_ACTION_TRIG_ORD,
.msg_id = msgid,
.slot_io = (WRTD_IN_FD_CONTROL << 4) |
(WRTD_OUT_FD_CONTROL & 0xF),
.flags = WRNC_PROTO_FLAG_SYNC,
......@@ -143,6 +146,17 @@ static int wrtd_out_trigger_order(struct wrtd_desc *wrtd, uint32_t tid)
return 0;
}
static int wrtd_out_trigger_insert(struct wrtd_desc *wrtd, uint32_t tid)
{
return wrtd_out_trigger_hash(wrtd, tid, WRTD_OUT_ACTION_TRIG_ADD);
}
static int wrtd_out_trigger_remove(struct wrtd_desc *wrtd, uint32_t tid)
{
return wrtd_out_trigger_hash(wrtd, tid, WRTD_OUT_ACTION_TRIG_DEL);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * PROTOTYPEs IMPLEMENTATION * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
......@@ -320,6 +334,70 @@ static int wrtd_out_trig_assign_condition_by_index(struct wrtd_node *dev,
return wrnc_rt_structure_set(wrtd->wrnc, &hdr, &tlv, 1);
}
/**
* It sets the given bitmaks (it means that it does OR with the current value)
*/
static int wrtd_out_flag_set(struct wrtd_node *dev, unsigned int output,
uint32_t flags)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct wrnc_structure_tlv tlv = {
.index = OUT_STRUCT_CHAN_0 + output,
.size = sizeof(struct wrtd_out_channel)
- sizeof(struct wrtd_out_channel_private),
.structure = &chan,
};
struct wrnc_proto_header hdr = hdr_base_sync;
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = wrnc_rt_structure_get(wrtd->wrnc, &hdr, &tlv, 1);
if (err)
return err;
chan.config.flags |= flags;
return wrnc_rt_structure_set(wrtd->wrnc, &hdr, &tlv, 1);
}
/**
* It sets the given bitmaks (it means that it does AND NOT with the current
* value)
*/
static int wrtd_out_flag_clr(struct wrtd_node *dev, unsigned int output,
uint32_t flags)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_out_channel chan;
struct wrnc_structure_tlv tlv = {
.index = OUT_STRUCT_CHAN_0 + output,
.size = sizeof(struct wrtd_out_channel)
- sizeof(struct wrtd_out_channel_private),
.structure = &chan,
};
struct wrnc_proto_header hdr = hdr_base_sync;
int err;
if (output >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = wrnc_rt_structure_get(wrtd->wrnc, &hdr, &tlv, 1);
if (err)
return err;
chan.config.flags &= ~flags;
return wrnc_rt_structure_set(wrtd->wrnc, &hdr, &tlv, 1);
}
static int wrtd_out_trig_assign_one(struct wrtd_node *dev, unsigned int output,
struct wrtd_trigger_handle *handle,
struct wrtd_trig_id *tid)
......@@ -341,24 +419,14 @@ static int wrtd_out_trig_assign_one(struct wrtd_node *dev, unsigned int output,
}
ret = wrtd_out_trigger_index_get(wrtd, tid);
if (ret < 0) {
handle->ptr_trig = wrtd_out_trigger_first_free(dev);
if (handle->ptr_trig < 0)
return -1;
} else {
handle->ptr_trig = ret;
}
if (ret < 0)
return ret;
handle->ptr_trig = ret;
tlv.index += handle->ptr_trig;
err = wrnc_rt_structure_get(wrtd->wrnc, &hdr, &tlv, 1);
if (err)
return err;
if (trig.flags & ENTRY_FLAG_VALID) {
errno = EINVAL;
return -1;
}
trig.flags |= ENTRY_FLAG_VALID;
trig.id = *tid;
memset(&trig.ocfg[handle->channel], 0, sizeof(struct lrt_output_rule));
......@@ -371,7 +439,11 @@ static int wrtd_out_trig_assign_one(struct wrtd_node *dev, unsigned int output,
if (err)
return err;
return wrtd_out_trigger_order(wrtd, handle->ptr_trig);
err = wrtd_out_trigger_insert(wrtd, handle->ptr_trig);
if (err)
return err;
return wrtd_out_flag_set(dev, handle->channel, WRTD_TRIGGER_ASSIGNED);
}
......@@ -423,6 +495,7 @@ int wrtd_out_trig_unassign(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_output_trigger_state triggers[256];
struct wrtd_out_trigger trig;
struct wrnc_structure_tlv tlv = {
.index = __WRTD_OUT_STRUCT_MAX + handle->ptr_trig,
......@@ -451,7 +524,16 @@ int wrtd_out_trig_unassign(struct wrtd_node *dev,
err = wrnc_rt_structure_set(wrtd->wrnc, &hdr, &tlv, 1);
if (err)
return err;
return wrtd_out_trigger_order(wrtd, handle->ptr_trig);
err = wrtd_out_trigger_remove(wrtd, handle->ptr_trig);
if (err)
return err;
err = wrtd_out_trig_get_all(dev, handle->channel, triggers, 256);
if (err < 0)
return -1;
if (err > 0)
return 0;
return wrtd_out_flag_clr(dev, handle->channel, WRTD_TRIGGER_ASSIGNED);
}
......@@ -468,6 +550,7 @@ int wrtd_out_trig_get_all(struct wrtd_node *dev, unsigned int output,
struct wrtd_output_trigger_state *triggers,
int max_count)
{
struct wrtd_output_trigger_state tmp;
int err = 0, i, count = 0;
if (output >= FD_NUM_CHANNELS) {
......@@ -475,9 +558,8 @@ int wrtd_out_trig_get_all(struct wrtd_node *dev, unsigned int output,
return -1;
}
for (i = 0; i < max_count && i < FD_HASH_ENTRIES; i++) {
err = wrtd_out_trig_state_get_by_index(dev, i, output,
&triggers[count]);
for (i = 0; count < max_count && i < FD_HASH_ENTRIES; i++) {
err = wrtd_out_trig_state_get_by_index(dev, i, output, &tmp);
if (err) {
if (errno == EWRTD_NOFOUND_TRIGGER) {
err = 0;
......@@ -486,6 +568,8 @@ int wrtd_out_trig_get_all(struct wrtd_node *dev, unsigned int output,
break;
}
} else {
memcpy(&triggers[count], &tmp,
sizeof(struct wrtd_output_trigger_state));
count++;
}
......@@ -571,11 +655,13 @@ int wrtd_out_trig_state_get_by_index(struct wrtd_node *dev, unsigned int index,
if (err)
return err;
if (!(trig.flags & ENTRY_FLAG_VALID)) {
if (!(trig.flags & ENTRY_FLAG_VALID) ||
(trig.ocfg[output].state == HASH_ENT_EMPTY)) {
errno = EWRTD_NOFOUND_TRIGGER;
return -1;
}
memset(trigger, 0, sizeof(struct wrtd_output_trigger_state));
trigger->handle.channel = output;
trigger->handle.ptr_trig = index;
trigger->handle.ptr_cond = (uint32_t)trig.ocfg[output].cond_ptr;
......
......@@ -8,6 +8,6 @@ WRNC = ../../../../
EXTRA_CFLAGS += -I../../include
EXTRA_CFLAGS += -I../common
EXTRA_CFLAGS += -DLIBRT_ERROR
EXTRA_CFLAGS += -DLIBRT_DEBUG
#EXTRA_CFLAGS += -DLIBRT_DEBUG
RT_USE_LIBRT := 1
include $(WRNC)/applications/common/rt/Makefile
......@@ -103,8 +103,7 @@ int wr_is_timing_ok()
struct wrtd_out_trigger triggers[FD_HASH_ENTRIES]; /**< list of triggers */
struct wrtd_out_trigger *ord_tlist[FD_HASH_ENTRIES]; /**< list of triggers
ordered by 'id' */
struct wrtd_out_trigger *ht[FD_HASH_ENTRIES]; /* hash table */
unsigned int tlist_count = 0; /**< number of valid trigger entry
in tlist */
static struct wrtd_out_channel wrtd_out_channels[FD_NUM_CHANNELS]; /**< Output
......@@ -112,67 +111,53 @@ static struct wrtd_out_channel wrtd_out_channels[FD_NUM_CHANNELS]; /**< Output
array */
static struct wrtd_out wrtd_out_device;
int trigger_search(struct wrtd_out_trigger **tlist,
struct wrtd_trig_id *id,
unsigned int min, unsigned int max,
unsigned int *mid)
{
int cmp;
#if 0
/* Binary search */
while (max > min)
{
*mid = min + (max - min) / 2;
cmp = memcmp(&tlist[*mid]->id, id, sizeof(struct wrtd_trig_id));
if(cmp == 0)
return 1;
else if (cmp < 0)
min = *mid + 1;
else
max = *mid - 1;
}
/* When we do not find our element, then mid + 1 is the ideal position
for a the new entry */
*mid++;
#else
/* FIXME Temporary HACK to be able to use memcmp
(smem not byte addressable - VHDL problem) */
volatile struct wrtd_trig_id tmp;
tmp.system = id->system;
tmp.source_port = id->source_port;
tmp.trigger = id->trigger;
for (*mid = min; *mid < max; (*mid)++) {
cmp = memcmp(&tlist[*mid]->id, &tmp, sizeof(struct wrtd_trig_id));
if (cmp == 0)
return 1;
else if (cmp > 0)
break;
}
#endif
static void print_hash_table(void)
{
int i;
#ifdef RTDEBUG
pp_printf("%s:%d %d %d %d %d - trig ID %d:%d:%d == %d:%d:%d ?\n",
__func__, __LINE__,
cmp, min, *mid, max,
tlist[*mid]->id.system, tlist[*mid]->id.source_port, tlist[*mid]->id.trigger,
id->system, id->source_port, id->trigger);
#endif
return 0;
pp_printf("%s <><><><><><>\n", __func__);
for (i = 0; i < FD_HASH_ENTRIES; ++i) {
delay(100000);
if (ht[i]) {
pp_printf("%s [%d]=%d:%d:%d - %p\n", __func__,
i, ht[i]->id.system,
ht[i]->id.source_port,
ht[i]->id.trigger,
&ht[i]);
} else {
pp_printf("%s [%d]=--:--:-- - %p\n", __func__,
i);
}
}
pp_printf("%s ==========\n", __func__);
}
static inline int trig_eq(struct wrtd_trig_id *id1, struct wrtd_trig_id *id2)
{
return id1->system == id2->system &&
id1->source_port == id2->source_port &&
id1->trigger == id2->trigger;
}
struct wrtd_out_trigger *rtfd_trigger_entry_find(struct wrtd_trig_id *id)
static int wrtd_out_hash_table_find(struct wrtd_trig_id *tid)
{
unsigned int index;
int ret;
int hidx;
for (hidx = wrtd_hash_func(tid); hidx < FD_HASH_ENTRIES; hidx++)
if (trig_eq(tid, &ht[hidx]->id))
return hidx;
ret = trigger_search(ord_tlist, id, 0, tlist_count, &index);
return -1;
}
static inline struct wrtd_out_trigger *rtfd_trigger_entry_find(struct wrtd_trig_id *tid)
{
int hidx = wrtd_out_hash_table_find(tid);
return ret ? ord_tlist[index] : NULL;
return hidx >= 0 ? ht[hidx] : NULL;
}
......@@ -577,6 +562,7 @@ void enqueue_trigger(int output, struct lrt_output_rule *rule,
}
static void filter_trigger(struct wrtd_trigger_entry *trig)
{
struct wrtd_out_trigger *ent = rtfd_trigger_entry_find(&trig->id);
......@@ -679,69 +665,78 @@ static int wrtd_out_trigger_sw(struct wrnc_proto_header *hin, void *pin,
return 0;
}
/**
* Clear order array by removing unused triggers
*/
static inline void wrtd_out_trigger_order_remove(void)
{
int i, k;
pp_printf("%s >> qua (%d)\n", __func__, tlist_count);
for (i = 0; i < tlist_count; i++) {
pp_printf("%s --- qua (%d/%d)\n", __func__, i, tlist_count);
if (ord_tlist[i]->flags & ENTRY_FLAG_VALID)
continue;
/* Found a removed trigger */
for (k = i; k < tlist_count - 1; k++)
ord_tlist[k] = ord_tlist[k + 1];
ord_tlist[k] = NULL;
tlist_count--;
static int wrtd_out_hash_table_free(struct wrtd_trig_id *tid)
{
int hidx = wrtd_hash_func(tid);
for (; hidx < FD_HASH_ENTRIES; hidx++) {
if (!ht[hidx])
return hidx;
/* Check if it already exists */
if (trig_eq(tid, &ht[hidx]->id))
break;
}
pp_printf("%s <<< qua (%d)\n", __func__, tlist_count);
return -1;
}
/**
* Insert a trigger the ordered array
*/
static inline void wrtd_out_trigger_order_insert(unsigned int trig_idx)
static int wrtd_out_hash_table_insert(struct wrnc_proto_header *hin, void *pin,
struct wrnc_proto_header *hout, void *pout)
{
int ret, index = 0, k;
uint32_t tidx = *(uint32_t *)pin;
int hidx;
pp_printf("%s >>> qua trig %d\n", __func__, trig_idx);
ret = trigger_search(ord_tlist, &triggers[trig_idx].id, 0,
tlist_count, &index);
if (ret) {
pp_printf("%s: trigger already there\n");
return;
if (tlist_count >= FD_HASH_ENTRIES) {
pp_printf("Too many triggers %d/%d\n",
tlist_count, FD_HASH_ENTRIES);
return -1;
}
pp_printf("%s --- qua\n", __func__);
for (k = tlist_count - 1; k >= index; --k)
ord_tlist[k + 1] = ord_tlist[k];
ord_tlist[index] = &triggers[trig_idx];
if (!(triggers[tidx].flags & ENTRY_FLAG_VALID))
return; /* nothing to do is a valid trigger */
hidx = wrtd_out_hash_table_free(&triggers[tidx].id);
if (hidx < 0)
goto out;
if (hidx >= FD_HASH_ENTRIES)
return -1;
tlist_count++;
pp_printf("%s <<< qua trig %d\n", __func__, trig_idx);
ht[hidx] = &triggers[tidx];
out:
rt_send_ack(hin, pin, hout, pout);
// print_hash_table();
return 0;
}
/**
* It order the triggers by ID
*/
static int wrtd_out_trigger_order(struct wrnc_proto_header *hin, void *pin,
struct wrnc_proto_header *hout, void *pout)
static int wrtd_out_hash_table_remove(struct wrnc_proto_header *hin, void *pin,
struct wrnc_proto_header *hout, void *pout)
{
uint32_t *trig_idx = pin;
uint32_t tidx = *(uint32_t *)pin;
int hidx;
pp_printf("%s >>> qua\n", __func__);
if (hin->len != 1) {
pp_printf("%s: command does not have payload, got %d bytes\n",
__func__, hin->len * 4);
if (tlist_count <= 0) {
pp_printf("No trigger to remove %d/%d\n",
tlist_count, FD_HASH_ENTRIES);
return -1;
}
wrtd_out_trigger_order_remove();
wrtd_out_trigger_order_insert(*trig_idx);
if (triggers[tidx].flags & ENTRY_FLAG_VALID)
return; /* nothing to do is a valid trigger */
hidx = wrtd_out_hash_table_find(&triggers[tidx].id);
if (hidx < 0)
return -1;
tlist_count--;
ht[hidx] = NULL;
rt_send_ack(hin, pin, hout, pout);
// print_hash_table();
pp_printf("%s <<< qua\n", __func__);
rt_send_ack(hin, pin, hout, NULL);
return 0;
}
......@@ -754,9 +749,9 @@ static int wrtd_out_trigger_index(struct wrnc_proto_header *hin, void *pin,
{
struct wrtd_trig_id *id = pin;
uint32_t *index = pout;
int hidx;
int ret;
pp_printf("%s --- qua\n", __func__);
/* Verify that the size is correct */
if (hin->len * 4 != sizeof(struct wrtd_trig_id)) {
pp_printf("%s: wrong incoming message size %d (expected %d)\n",
......@@ -769,15 +764,24 @@ static int wrtd_out_trigger_index(struct wrnc_proto_header *hin, void *pin,
}
ret = trigger_search(ord_tlist, id, 0, tlist_count,
(unsigned int *) index);
pp_printf("%s --- qua -- %d:%d:%d %d %d\n", __func__,
id->system, id->source_port, id->trigger, ret, *index);
if (ret) {
/* hout.msg_id = TODO ; */
hout->len = 1;
return 0;
hidx = wrtd_out_hash_table_find(id);
if (hidx >= 0) {
*index = ((int)ht[hidx] - (int)triggers) / sizeof(struct wrtd_out_trigger);
} else {
/* Get first free */
for (*index = 0; *index < FD_HASH_ENTRIES; ++(*index)) {
if (!(triggers[*index].flags & ENTRY_FLAG_VALID)) {
hout->msg_id = WRTD_OUT_ACTION_TRIG_FRE;
break;
}
}
if ((*index) == FD_HASH_ENTRIES)
return -1;
}
hout->len = 1;
return 0;
err:
return -1;
}
......@@ -817,7 +821,8 @@ static action_t *wrtd_out_actions[] = {
[RT_ACTION_RECV_STRUCT_GET] = rt_structure_getter,
[WRTD_OUT_ACTION_SW_TRIG] = wrtd_out_trigger_sw,
[WRTD_OUT_ACTION_TRIG_IDX] = wrtd_out_trigger_index,
[WRTD_OUT_ACTION_TRIG_ORD] = wrtd_out_trigger_order,
[WRTD_OUT_ACTION_TRIG_ADD] = wrtd_out_hash_table_insert,
[WRTD_OUT_ACTION_TRIG_DEL] = wrtd_out_hash_table_remove,
};
enum rt_slot_name {
......@@ -900,7 +905,7 @@ void init(void)
/* Triggers */
for (i = 0; i < FD_HASH_ENTRIES; i++) {
memset(&triggers[i], 0, sizeof(struct wrtd_out_trigger));
ord_tlist[i] = NULL;
ht[i] = NULL;
}
/* librt: dynamically add structures */
......
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