summaryrefslogtreecommitdiffstats
path: root/src/target/firmware
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-05-07 16:46:47 +0200
committerHarald Welte <laforge@gnumonks.org>2010-05-17 09:23:35 +0200
commitea3b3826f2c8650d36d033e99a7af08c05ef562a (patch)
tree1e490b0828cd373be6e412b2d6589c0e1e0d9e9d /src/target/firmware
parent452bc184700841744884e4675db5e3bc520198d5 (diff)
layer1: introduce concept of a 'l1 completion'
The idea is that the L1S part can schedule a completion handler which will then execute in the asynchronous L1A part. This should keep the FIQ priority L1S extremely short, deferring most of the work into the L1A part that runs in regular process context.
Diffstat (limited to 'src/target/firmware')
-rw-r--r--src/target/firmware/include/layer1/async.h3
-rw-r--r--src/target/firmware/include/layer1/sync.h15
-rw-r--r--src/target/firmware/layer1/async.c23
-rw-r--r--src/target/firmware/layer1/sync.c10
4 files changed, 51 insertions, 0 deletions
diff --git a/src/target/firmware/include/layer1/async.h b/src/target/firmware/include/layer1/async.h
index 33f89bc1..03e33ca5 100644
--- a/src/target/firmware/include/layer1/async.h
+++ b/src/target/firmware/include/layer1/async.h
@@ -29,6 +29,9 @@ void l1a_mftask_enable(enum mframe_task task);
/* Disable a repeating multiframe task */
void l1a_mftask_disable(enum mframe_task task);
+/* Execute pending L1A completions */
+void l1a_compl_execute(void);
+
/* Initialize asynchronous part of Layer1 */
void l1a_init(void);
diff --git a/src/target/firmware/include/layer1/sync.h b/src/target/firmware/include/layer1/sync.h
index d053c93f..fc8b7772 100644
--- a/src/target/firmware/include/layer1/sync.h
+++ b/src/target/firmware/include/layer1/sync.h
@@ -28,6 +28,13 @@ enum l1s_chan {
_NUM_L1S_CHAN
};
+enum l1_compl {
+ L1_COMPL_FB,
+};
+
+typedef void l1_compl_cb(enum l1_compl c);
+
+#define L1S_NUM_COMPL 32
#define L1S_NUM_NEIGH_CELL 6
struct l1s_state {
@@ -52,6 +59,11 @@ struct l1s_state {
/* Transmit queues of pending packets for main DCCH and ACCH */
struct llist_head tx_queue[_NUM_L1S_CHAN];
+ /* Which L1A completions are scheduled right now */
+ uint32_t scheduled_compl;
+ /* callbacks for each of the completions */
+ l1_compl_cb *completion[L1S_NUM_COMPL];
+
/* Structures below are for L1-task specific parameters, used
* to communicate between l1-sync and l1-async (l23_api) */
struct {
@@ -126,6 +138,9 @@ void l1s_sb_test(uint8_t base_fn);
void l1s_pm_test(uint8_t base_fn, uint16_t arfcn);
void l1s_nb_test(uint8_t base_fn);
+/* schedule a completion */
+void l1s_compl_sched(enum l1_compl c);
+
void l1s_init(void);
/* reset the layer1 as part of synchronizing to a new cell */
diff --git a/src/target/firmware/layer1/async.c b/src/target/firmware/layer1/async.c
index 3db07e11..dda4bf10 100644
--- a/src/target/firmware/layer1/async.c
+++ b/src/target/firmware/layer1/async.c
@@ -69,3 +69,26 @@ void l1a_init(void)
{
l1a_l23api_init();
}
+
+/* Execute pending L1A completions */
+void l1a_compl_execute(void)
+{
+ unsigned long flags;
+ unsigned int scheduled;
+ unsigned int i;
+
+ /* get and reset the currently scheduled tasks */
+ local_irq_save(flags);
+ scheduled = l1s.scheduled_compl;
+ l1s.scheduled_compl = 0;
+ local_irq_restore(flags);
+
+ /* Iterate over list of scheduled completions, call their
+ * respective completion handler */
+ for (i = 0; i < 32; i++) {
+ if (!(scheduled & (1 << i)))
+ continue;
+ /* call completion function */
+ l1s.completion[i](i);
+ }
+}
diff --git a/src/target/firmware/layer1/sync.c b/src/target/firmware/layer1/sync.c
index f5629cfc..9ca37ef0 100644
--- a/src/target/firmware/layer1/sync.c
+++ b/src/target/firmware/layer1/sync.c
@@ -200,6 +200,16 @@ static inline void check_lost_frame(void)
last_timestamp = timestamp;
}
+/* schedule a completion */
+void l1s_compl_sched(enum l1_compl c)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ l1s.scheduled_compl |= (1 << c);
+ local_irq_restore(flags);
+}
+
/* main routine for synchronous part of layer 1, called by frame interrupt
* generated by TPU once every TDMA frame */
static void l1_sync(void)