Here is a patch to add the option of joint slots. I have not had a chance to
fully test this but the changes are fairly confined so this should be good.
The basic idea is that you define multiple slots but all but the first are
defined as 'joined' to the first one. Then when you write via the socket,
the data goes to a common slot buffer and is sent in the next assigned slot.
This can be used to significantly reduce latencies without requiring very
short cycle periods.
The changes are:
1) add a -j option to tdmacfg for 'slots' which takes the joint slot id. It
will be required that the slot you want to reference to must have already
been defined before you define the joint slot. Also, the mtu's of both
the slot your joining and your own slot must be the same.
2) The tdma_config struct adds an additional int field called jointslot to
the set_slot union. A value between 0 and MaxSlots indicates a
desire to be coupled. Default is -1 (no coupling).
3) Modify the tdma_slot by changing the 'queue' member to be a pointer to a
rtskb_prio_queue and add an additional actual rtskb_prio_queue called
myqueue.
4) By default, slot->queue just points to &slot->myqueue.
5) The act of joining is achieved by changing slot->queue to point to
another pre-existing slot's myqueue member.
6) the rest of the tdma_slot structs for the two joint slots are not
identical because this is where things like offset, period and phasing info
are kept and those are different for the two slots. Only the
rtskb_prio_queue is common between them.
7) If you remove a slot which is jointed to another slot but you're not the
reference, then you just delete normally. But if others have queue pointer
pointing to your myqueue object then all those slots have their queue's
redirected to their own myqueue objects. Obviously, care is taken that this
is done when ref_count is 0 so we don't corrupt a loop in progress.
8) The only other impact is a few function calls which currently have
&slot->queue which needed to be changed to slot->queue since it's a pointer
already.
9) An unrelated bug was addressed, in the original tdma_ioctl.c file on line
474 the original code had
while ((rtskb = __rtskb_prio_dequeue(&slot->queue)))
but I believe the correct call should have been
while ((rtskb = __rtskb_prio_dequeue(&old_slot->queue)))
I've incorporated that into this patch as well but it is really independent
of the joint-slots changes.
Unlike what I stated in an earlier post, this no longer treats the NRT slot
any different from the others, thus you can also join to it if you want.
Regards,
Bill
********* patch ************************
diff -Naur rtnet-0.8.3/stack/include/rtmac/tdma/tdma.h
rtnet-0.8.3new/stack/include/rtmac/tdma/tdma.h
--- rtnet-0.8.3/stack/include/rtmac/tdma/tdma.h 2005-02-28
04:27:34.000000000 -0600
+++ rtnet-0.8.3new/stack/include/rtmac/tdma/tdma.h 2005-08-18
08:39:22.000000000 -0500
@@ -78,7 +78,8 @@
unsigned int phasing;
unsigned int mtu;
unsigned int size;
- struct rtskb_prio_queue queue;
+ struct rtskb_prio_queue *queue;
+ struct rtskb_prio_queue myqueue;
};
diff -Naur rtnet-0.8.3/stack/include/tdma_chrdev.h
rtnet-0.8.3new/stack/include/tdma_chrdev.h
--- rtnet-0.8.3/stack/include/tdma_chrdev.h 2004-11-17
02:09:44.000000000 -0600
+++ rtnet-0.8.3new/stack/include/tdma_chrdev.h 2005-08-18
08:40:02.000000000 -0500
@@ -54,6 +54,7 @@
unsigned int period;
unsigned int phasing;
unsigned int size;
+ int jointslot;
unsigned int cal_timeout;
__u64 *cal_results;
} set_slot;
diff -Naur rtnet-0.8.3/stack/rtmac/tdma/tdma_ioctl.c
rtnet-0.8.3new/stack/rtmac/tdma/tdma_ioctl.c
--- rtnet-0.8.3/stack/rtmac/tdma/tdma_ioctl.c 2005-02-28
04:27:34.000000000 -0600
+++ rtnet-0.8.3new/stack/rtmac/tdma/tdma_ioctl.c 2005-08-18
02:54:34.000000000 -0500
@@ -299,7 +299,7 @@
struct rtskb *rtskb;
unsigned int job_list_revision;
unsigned long flags;
- int ret;
+ int ret, ii, jntId;
if (rtdev->mac_priv == NULL)
@@ -318,6 +318,15 @@
else if (cfg->args.set_slot.size > rtdev->mtu)
return -EINVAL;
+ jntId = cfg->args.set_slot.jointslot;
+ if( (jntId >=0 ) &&
+ ( (jntId >= tdma->max_slot_id)
+ || (tdma->slot_table[jntId] == 0)
+ || (tdma->slot_table[jntId]->mtu != cfg->args.set_slot.size)
+ ) )
+ return -EINVAL;
+
+
slot = (struct tdma_slot *)kmalloc(sizeof(struct tdma_slot),
GFP_KERNEL);
if (!slot)
return -ENOMEM;
@@ -402,8 +411,12 @@
slot->phasing = cfg->args.set_slot.phasing;
slot->mtu = cfg->args.set_slot.size;
slot->size = cfg->args.set_slot.size +
rtdev->hard_header_len;
+ slot->queue = &slot->myqueue;
rtos_nanosecs_to_time(cfg->args.set_slot.offset, &slot->offset);
- rtskb_prio_queue_init(&slot->queue);
+ rtskb_prio_queue_init(slot->queue);
+
+ if(jntId >=0 ) //all other validation tests performed above.
+ slot->queue = tdma->slot_table[jntId]->queue;
old_slot = tdma->slot_table[id];
if ((id == DEFAULT_NRT_SLOT) &&
@@ -454,13 +467,27 @@
(tdma->slot_table[DEFAULT_NRT_SLOT] == old_slot))
tdma->slot_table[DEFAULT_NRT_SLOT] = slot;
- if (old_slot)
+ if (old_slot) {
while (old_slot->head.ref_count > 0) {
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/10); /* wait 100 ms */
rtos_spin_lock_irqsave(&tdma->lock, flags);
}
+ //if others were linked to my prio que, move them to the new one.
+ for(ii=0; ii<tdma->max_slot_id; ii++) {
+ if( (tdma->slot_table[ii] != 0)
+ && (tdma->slot_table[ii]->queue == &old_slot->myqueue)) {
+ while (tdma->slot_table[ii]->head.ref_count > 0) {
+ rtos_spin_unlock_irqrestore(&tdma->lock, flags);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10); /* wait 100 ms */
+ rtos_spin_lock_irqsave(&tdma->lock, flags);
+ } //end while, safe to change queue pointer
+ tdma->slot_table[ii]->queue = slot->queue;
+ }
+ }
+ }
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
@@ -471,7 +498,8 @@
without lock protection.
NOTE: Reconfiguring a slot during runtime may lead to packet
drops! */
- while ((rtskb = __rtskb_prio_dequeue(&slot->queue)))
+ old_slot->queue = &old_slot->myqueue;
+ while ((rtskb = __rtskb_prio_dequeue(old_slot->queue)))
kfree_rtskb(rtskb);
kfree(old_slot);
@@ -501,10 +529,24 @@
if (id == DEFAULT_NRT_SLOT)
tdma->slot_table[DEFAULT_NRT_SLOT] =
tdma->slot_table[DEFAULT_SLOT];
else {
+ int ii;
if ((id == DEFAULT_SLOT) &&
(tdma->slot_table[DEFAULT_NRT_SLOT] == slot))
tdma->slot_table[DEFAULT_NRT_SLOT] = NULL;
tdma->slot_table[id] = NULL;
+ //search for other slots linked to my queue and detach them
+ for(ii=0; ii<tdma->max_slot_id; ii++) {
+ if( (tdma->slot_table[ii] != 0) &&
+ (tdma->slot_table[ii]->queue == &slot->myqueue)) {
+ while (tdma->slot_table[ii]->head.ref_count > 0) {
+ rtos_spin_unlock_irqrestore(&tdma->lock, flags);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10); /* wait 100 ms */
+ rtos_spin_lock_irqsave(&tdma->lock, flags);
+ } //end while, safe to move queue pointer
+ tdma->slot_table[ii]->queue =
&tdma->slot_table[ii]->myqueue;
+ }
+ }
}
while (slot->head.ref_count > 0) {
@@ -518,7 +560,8 @@
/* No need to protect the queue access here -
no one is referring to this job anymore (ref_count == 0). */
- while ((rtskb = __rtskb_prio_dequeue(&slot->queue)))
+ slot->queue = &slot->myqueue;
+ while ((rtskb = __rtskb_prio_dequeue(slot->queue)))
kfree_rtskb(rtskb);
kfree(slot);
diff -Naur rtnet-0.8.3/stack/rtmac/tdma/tdma_proto.c
rtnet-0.8.3new/stack/rtmac/tdma/tdma_proto.c
--- rtnet-0.8.3/stack/rtmac/tdma/tdma_proto.c 2005-02-28
04:27:34.000000000 -0600
+++ rtnet-0.8.3new/stack/rtmac/tdma/tdma_proto.c 2005-08-18
09:00:04.000000000 -0500
@@ -155,7 +155,7 @@
goto err_out;
}
- __rtskb_prio_queue_tail(&slot->queue, rtskb);
+ __rtskb_prio_queue_tail(slot->queue, rtskb);
err_out:
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
@@ -193,7 +193,7 @@
goto err_out;
}
- __rtskb_prio_queue_tail(&slot->queue, rtskb);
+ __rtskb_prio_queue_tail(slot->queue, rtskb);
err_out:
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
diff -Naur rtnet-0.8.3/stack/rtmac/tdma/tdma_worker.c
rtnet-0.8.3new/stack/rtmac/tdma/tdma_worker.c
--- rtnet-0.8.3/stack/rtmac/tdma/tdma_worker.c 2004-12-06
02:10:44.000000000 -0600
+++ rtnet-0.8.3new/stack/rtmac/tdma/tdma_worker.c 2005-08-18
09:00:48.000000000 -0500
@@ -58,7 +58,7 @@
rtos_task_sleep_until(&time);
rtos_spin_lock_irqsave(&tdma->lock, flags);
- rtskb = __rtskb_prio_dequeue(&SLOT_JOB(job)->queue);
+ rtskb = __rtskb_prio_dequeue(SLOT_JOB(job)->queue);
if (!rtskb)
goto continue_in_lock;
rtos_spin_unlock_irqrestore(&tdma->lock, flags);
diff -Naur rtnet-0.8.3/tools/tdmacfg.c rtnet-0.8.3new/tools/tdmacfg.c
--- rtnet-0.8.3/tools/tdmacfg.c 2004-12-02 03:39:38.000000000 -0600
+++ rtnet-0.8.3new/tools/tdmacfg.c 2005-08-18 09:05:38.000000000 -0500
@@ -44,7 +44,7 @@
"\t [-m max_calibration_requests]\n"
"\ttdmacfg <dev> slave [-c calibration_rounds] [-i max_slot_id]\n"
"\ttdmacfg <dev> slot <id> [<offset> [-p <phasing>/<period>] "
- "[-s <size>]\n"
+ "[-s <size>] [-j <joint_slot_id>]\n"
"\t [-l calibration_log_file] [-t calibration_timeout]]\n"
"\ttdmacfg <dev> detach\n");
@@ -60,7 +60,7 @@
if (pos >= argc)
help();
- if ((sscanf(argv[pos], "%u", &result) != 1) || (result < min)) {
+ if ((sscanf(argv[pos], "%i", &result) != 1) || (result < min)) {
fprintf(stderr, "invalid parameter: %s %s\n", argv[pos-1],
argv[pos]);
exit(1);
}
@@ -208,6 +208,7 @@
tdma_cfg.args.set_slot.phasing = 0;
tdma_cfg.args.set_slot.size = 0;
tdma_cfg.args.set_slot.cal_timeout = 0;
+ tdma_cfg.args.set_slot.jointslot = -1;
tdma_cfg.args.set_slot.cal_results = NULL;
for (i = 5; i < argc; i++) {
@@ -236,6 +237,9 @@
else if (strcmp(argv[i], "-t") == 0)
tdma_cfg.args.set_slot.cal_timeout =
getintopt(argc, ++i, argv, 0);
+ else if (strcmp(argv[i], "-j") == 0)
+ tdma_cfg.args.set_slot.jointslot =
+ getintopt(argc, ++i, argv, -1);
else
help();
}
|