summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Schodet2012-01-09 13:31:34 +0100
committerNicolas Schodet2012-01-09 13:31:34 +0100
commitbb1b146db561ae58f339224b56c1acd3b661f18f (patch)
tree970871998d1abf9784f109b46254cb4564307970
parentf5c6b799cdce5b4bb1618f4789bb683efa7967ab (diff)
parent7aade45c20b0fa20bc15e349fa9e381dbb634fc3 (diff)
Merge branch 'cpu-starvation'
-rw-r--r--cesar/ecos/packages/kernel/current/cdl/interrupts.cdl25
-rw-r--r--cesar/ecos/packages/kernel/current/include/intr.hxx25
-rw-r--r--cesar/ecos/packages/kernel/current/src/intr/intr.cxx82
-rw-r--r--cesar/ecos/packages/kernel/current/src/sched/sched.cxx3
-rw-r--r--cesar/hal/arch/inc/ecos.h1
-rw-r--r--cesar/mac/common/src/store.c118
6 files changed, 222 insertions, 32 deletions
diff --git a/cesar/ecos/packages/kernel/current/cdl/interrupts.cdl b/cesar/ecos/packages/kernel/current/cdl/interrupts.cdl
index f6c02c1222..2d2fb35f6e 100644
--- a/cesar/ecos/packages/kernel/current/cdl/interrupts.cdl
+++ b/cesar/ecos/packages/kernel/current/cdl/interrupts.cdl
@@ -126,4 +126,29 @@ cdl_component CYGIMP_KERNEL_INTERRUPTS_DSRS {
inspecting the device itself. It can also reduce the amount
of RAM needed for interrupt decoding tables and code."
}
+
+ cdl_component CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT {
+ display "Limit time spent in DSRs"
+ default_value CYGPKG_HAL_SPARC_LEON
+ description "
+ Limit time spent in DSRs and reserve some time to be used by
+ threads. Time unit is millisecond."
+
+ cdl_option CYGNUM_KERNEL_INTERRUPTS_DSRS_LIMIT_DSR_TIME_MAX {
+ display "DSR time maximum limit"
+ flavor data
+ default_value 296
+ description "
+ Time limit after which thread time is examined. If thread did
+ not get enough time, DSR execution is suspended."
+ }
+
+ cdl_option CYGNUM_KERNEL_INTERRUPTS_DSRS_LIMIT_THREAD_TIME_MIN {
+ display "Thread time minimum limit"
+ flavor data
+ default_value 4
+ description "
+ Minimum time to reserve for thread execution."
+ }
+ }
}
diff --git a/cesar/ecos/packages/kernel/current/include/intr.hxx b/cesar/ecos/packages/kernel/current/include/intr.hxx
index d10f98fc70..1e380189a3 100644
--- a/cesar/ecos/packages/kernel/current/include/intr.hxx
+++ b/cesar/ecos/packages/kernel/current/include/intr.hxx
@@ -156,6 +156,9 @@ class Cyg_Interrupt
static void call_pending_DSRs();
static void call_pending_DSRs_inner();
+ // Check for disabled DSRs
+ static cyg_bool DSRs_disabled();
+
// DSR handling interface called by the scheduler and HAL
// interrupt arbiters.
@@ -206,6 +209,19 @@ class Cyg_Interrupt
#endif
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+
+ // Time spent in DSR
+ static cyg_uint32 dsr_time;
+ // Time spent in thread while DSR are suspended
+ static cyg_uint32 thread_prio_time;
+ // Enter date of thread while DSR are suspended
+ static cyg_uint32 thread_prio_enter_date;
+ // DSR are suspended if true
+ static cyg_bool thread_prio;
+
+#endif
+
#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN
// The default mechanism for handling interrupts is to attach just
@@ -369,6 +385,15 @@ inline cyg_bool Cyg_Interrupt::DSRs_pending()
#endif
};
+
+inline cyg_bool Cyg_Interrupt::DSRs_disabled()
+{
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+ return thread_prio;
+#else
+ return false;
+#endif
+};
#endif // CYGIMP_KERNEL_INTERRUPTS_DSRS
// -------------------------------------------------------------------------
diff --git a/cesar/ecos/packages/kernel/current/src/intr/intr.cxx b/cesar/ecos/packages/kernel/current/src/intr/intr.cxx
index 71b9de1f04..c152bc259f 100644
--- a/cesar/ecos/packages/kernel/current/src/intr/intr.cxx
+++ b/cesar/ecos/packages/kernel/current/src/intr/intr.cxx
@@ -66,6 +66,10 @@
#include "hal/trace/trace_cpu_foreign.h"
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+#include "hal/arch/time.h"
+#endif
+
// -------------------------------------------------------------------------
// Statics
@@ -142,6 +146,20 @@ Cyg_Interrupt* volatile Cyg_Interrupt::dsr_list_tail[CYGNUM_KERNEL_CPU_MAX];
#endif
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+
+cyg_uint32 Cyg_Interrupt::dsr_time;
+cyg_uint32 Cyg_Interrupt::thread_prio_time;
+cyg_uint32 Cyg_Interrupt::thread_prio_enter_date;
+cyg_bool Cyg_Interrupt::thread_prio;
+
+#define THREAD_TIME_MIN (CYGNUM_KERNEL_INTERRUPTS_DSRS_LIMIT_THREAD_TIME_MIN \
+ * ARCH_TIME_FREQ_MHZ * 1000)
+#define DSR_TIME_MAX (CYGNUM_KERNEL_INTERRUPTS_DSRS_LIMIT_DSR_TIME_MAX \
+ * ARCH_TIME_FREQ_MHZ * 1000)
+
+#endif
+
// -------------------------------------------------------------------------
// Call any pending DSRs
@@ -150,6 +168,37 @@ Cyg_Interrupt::call_pending_DSRs_inner(void)
{
// CYG_REPORT_FUNCTION();
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+#if CYGNUM_KERNEL_CPU_MAX != 1
+# error "not implemented for several CPU"
+#endif
+
+ extern Cyg_Thread idle_thread;
+ cyg_uint32 now;
+ cyg_uint32 dsr_enter_date;
+
+ if (thread_prio)
+ {
+ now = *(volatile cyg_uint32 *) ARCH_TIME_ADDR;
+ thread_prio_time += now - thread_prio_enter_date;
+ if ((Cyg_Scheduler::get_current_thread() != &idle_thread
+ || Cyg_Scheduler::get_need_reschedule())
+ && thread_prio_time < THREAD_TIME_MIN)
+ {
+ thread_prio_enter_date = now;
+ return;
+ }
+ else
+ {
+ thread_prio = false;
+ thread_prio_time = 0;
+ }
+ }
+
+ dsr_enter_date = *(volatile cyg_uint32 *) ARCH_TIME_ADDR;
+
+#endif
+
HAL_SMP_CPU_TYPE cpu = CYG_KERNEL_CPU_THIS();
#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE
@@ -167,6 +216,14 @@ Cyg_Interrupt::call_pending_DSRs_inner(void)
CYG_ASSERT( intr->dsr != NULL , "No DSR defined");
intr->dsr( intr->vector, 1, (CYG_ADDRWORD)intr->data );
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+ now = *(volatile cyg_uint32 *) ARCH_TIME_ADDR;
+ dsr_time += now - dsr_enter_date;
+ dsr_enter_date = now
+ if (dsr_time > DSR_TIME_MAX)
+ break;
+#endif
}
#endif
@@ -203,11 +260,30 @@ Cyg_Interrupt::call_pending_DSRs_inner(void)
#if HAL_TRACE_CPU
hal_trace_cpu (HAL_TRACE_CPU_DSR_RET_ID, 0, 0);
#endif
-
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+ now = *(volatile cyg_uint32 *) ARCH_TIME_ADDR;
+ dsr_time += now - dsr_enter_date;
+ dsr_enter_date = now;
+ if (dsr_time > DSR_TIME_MAX)
+ break;
+#endif
+ }
+
+#endif
+
+#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIMIT
+ if (dsr_time > DSR_TIME_MAX)
+ {
+ dsr_time = 0;
+ if (Cyg_Scheduler::get_current_thread() != &idle_thread
+ || Cyg_Scheduler::get_need_reschedule())
+ {
+ thread_prio = true;
+ thread_prio_enter_date = *(volatile cyg_uint32 *) ARCH_TIME_ADDR;
+ }
}
-
#endif
-
};
externC void
diff --git a/cesar/ecos/packages/kernel/current/src/sched/sched.cxx b/cesar/ecos/packages/kernel/current/src/sched/sched.cxx
index cf8249f941..63f894a818 100644
--- a/cesar/ecos/packages/kernel/current/src/sched/sched.cxx
+++ b/cesar/ecos/packages/kernel/current/src/sched/sched.cxx
@@ -266,7 +266,8 @@ void Cyg_Scheduler::unlock_inner( cyg_ucount32 new_lock )
// a DSR could have been posted during a reschedule, but would
// not be run until the _next_ time we release the sched lock.
- if( Cyg_Interrupt::DSRs_pending() ) {
+ if( Cyg_Interrupt::DSRs_pending()
+ && !Cyg_Interrupt::DSRs_disabled()) {
inc_sched_lock(); // reclaim the lock
continue; // go back to head of loop
}
diff --git a/cesar/hal/arch/inc/ecos.h b/cesar/hal/arch/inc/ecos.h
index c2fff33163..bfb5a1254c 100644
--- a/cesar/hal/arch/inc/ecos.h
+++ b/cesar/hal/arch/inc/ecos.h
@@ -86,6 +86,7 @@ arch_stop (void)
#else
cyg_drv_isr_lock ();
#endif
+ cyg_drv_dsr_lock ();
}
#define arch_reorder_barrier HAL_REORDER_BARRIER
diff --git a/cesar/mac/common/src/store.c b/cesar/mac/common/src/store.c
index f74cfaef83..724ab1827c 100644
--- a/cesar/mac/common/src/store.c
+++ b/cesar/mac/common/src/store.c
@@ -43,6 +43,8 @@ struct mac_store_sta_t
/** LLID MFS for RX from this STA. Only allocated when really needed, the
* first four pointers are not used. */
mfs_t **rx_llid;
+ /** Maximum RX LLID ever created, used for optimization. */
+ uint rx_llid_max;
};
typedef struct mac_store_sta_t mac_store_sta_t;
@@ -59,6 +61,10 @@ struct mac_store_t
* - 0x80-0xf7: TX/RX GLID
* - 0xf8-0xfd: unused & discover and central beacons */
mfs_t *lglid[MAC_LID_BEACON_MAX + 1];
+ /** Maximum TX LLID ever created, used for optimization. */
+ uint tx_llid_max;
+ /** Maximum GLID ever created, used for optimization. */
+ uint glid_max;
/** Peers, indexed by TEI. */
mac_store_sta_t *sta[MAC_TEI_STA_MAX + 1];
/** Unassociated MFS. */
@@ -80,6 +86,8 @@ mac_store_init (void)
ctx->bcast_tx_mme = NULL;
for (i = 0; i < COUNT (ctx->lglid); i++)
ctx->lglid[i] = NULL;
+ ctx->tx_llid_max = 0;
+ ctx->glid_max = 0;
for (i = 0; i < COUNT (ctx->sta); i++)
ctx->sta[i] = NULL;
list_init (&ctx->unassociated);
@@ -134,10 +142,18 @@ mac_store_mfs_slot_get (mac_store_t *ctx, bool tx, bool bcast, bool mme,
return NULL;
}
else
+ {
+ if (add && lid <= MAC_GLID_MAX)
+ ctx->glid_max = MAX (ctx->glid_max, lid);
return &ctx->lglid[lid];
+ }
}
else if (!mme && (tx && lid >= MAC_LLID_MIN))
+ {
+ if (add)
+ ctx->tx_llid_max = MAX (ctx->tx_llid_max, lid);
return &ctx->lglid[lid];
+ }
else if (tx && bcast && !mme && MAC_LID_IS_PLID (lid))
return &ctx->bcast_tx_plid[lid];
else if (tx && bcast && mme)
@@ -155,6 +171,8 @@ mac_store_mfs_slot_get (mac_store_t *ctx, bool tx, bool bcast, bool mme,
if (!mme && lid >= MAC_LLID_MIN)
{
dbg_blame (!tx && lid <= MAC_LLID_MAX);
+ if (add)
+ sta->rx_llid_max = MAX (sta->rx_llid_max, lid);
if (!sta->rx_llid)
{
if (add)
@@ -265,6 +283,7 @@ mac_store_mfs_alias_ (mac_store_t *ctx, mfs_t *mfs, uint glid __FL)
dbg_blame (ctx->lglid[glid] == NULL);
arch_dsr_lock ();
blk_addref_ (mfs __fl);
+ ctx->glid_max = MAX (ctx->glid_max, glid);
ctx->lglid[glid] = mfs;
/* Modify the MFS. */
mfs->common.lid_alias = mfs->common.lid;
@@ -347,25 +366,43 @@ mac_store_mfs_travel (mac_store_t *ctx, mac_store_travel_t travel,
void *user)
{
/* Will unlock DSR between each MFS fetch to reduce DSR latency. */
- int i;
+ uint i;
dbg_assert (ctx);
dbg_assert (travel);
/* First travel local MFS. */
for (i = 0; i < MAC_PLID_NB; i++)
{
- arch_dsr_lock ();
- mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->bcast_tx_plid[i],
- travel, user);
+ if (ctx->bcast_tx_plid[i])
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->bcast_tx_plid[i],
+ travel, user);
+ }
}
- arch_dsr_lock ();
- mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->bcast_tx_mme, travel,
- user);
- for (i = MAC_LLID_MIN; i < MAC_LID_NB; i++)
+ if (ctx->bcast_tx_mme)
{
arch_dsr_lock ();
- mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[i], travel,
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->bcast_tx_mme, travel,
user);
}
+ for (i = MAC_LLID_MIN; i <= ctx->tx_llid_max; i++)
+ {
+ if (ctx->lglid[i])
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[i], travel,
+ user);
+ }
+ }
+ for (i = MAC_GLID_MIN; i <= ctx->glid_max; i++)
+ {
+ if (ctx->lglid[i])
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[i], travel,
+ user);
+ }
+ }
/* Then unassociated MFS (DSR locked, to preserve list integrity). */
list_node_t *u, *uend, *unext;
arch_dsr_lock ();
@@ -378,15 +415,23 @@ mac_store_mfs_travel (mac_store_t *ctx, mac_store_travel_t travel,
}
arch_dsr_unlock ();
/* Do not forget beacon MFS. */
- arch_dsr_lock ();
- mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[MAC_LID_DISCOVER],
- travel, user);
- arch_dsr_lock ();
- mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[MAC_LID_SPC_CENTRAL],
- travel, user);
+ if (ctx->lglid[MAC_LID_DISCOVER])
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, ctx->lglid[MAC_LID_DISCOVER],
+ travel, user);
+ }
+ if (ctx->lglid[MAC_LID_SPC_CENTRAL])
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx,
+ ctx->lglid[MAC_LID_SPC_CENTRAL],
+ travel, user);
+ }
/* Now travel by TEI. */
for (i = MAC_TEI_STA_MIN; i <= MAC_TEI_STA_MAX; i++)
- mac_store_mfs_travel_by_tei (ctx, i, travel, user);
+ if (ctx->sta[i])
+ mac_store_mfs_travel_by_tei (ctx, i, travel, user);
}
void
@@ -414,26 +459,42 @@ mac_store_mfs_travel_by_tei (mac_store_t *ctx, uint tei,
{
for (j = 0; j < MAC_PLID_NB; j++)
{
+ if (sta->plid[i][j])
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (ctx, sta->plid[i][j],
+ travel, user);
+ }
+ }
+ if (sta->mme[i])
+ {
arch_dsr_lock ();
- mac_store_mfs_travel_mfs_and_unlock (ctx, sta->plid[i][j],
- travel, user);
+ mac_store_mfs_travel_mfs_and_unlock (ctx, sta->mme[i], travel,
+ user);
}
- arch_dsr_lock ();
- mac_store_mfs_travel_mfs_and_unlock (ctx, sta->mme[i], travel,
- user);
}
- for (i = MAC_LLID_MIN; i <= MAC_LLID_MAX; i++)
+ if (sta->rx_llid)
{
+ mfs_t **rx_llid;
arch_dsr_lock ();
- /* Do this test at each loop step as the scheduler is unlocked
- * between each step. */
- if (!sta->rx_llid)
+ rx_llid = sta->rx_llid;
+ if (rx_llid)
{
+ blk_addref (rx_llid);
arch_dsr_unlock ();
- break;
+ for (i = MAC_LLID_MIN; i <= sta->rx_llid_max; i++)
+ {
+ if (rx_llid[i])
+ {
+ arch_dsr_lock ();
+ mac_store_mfs_travel_mfs_and_unlock (
+ ctx, rx_llid[i], travel, user);
+ }
+ }
+ blk_release (rx_llid);
}
- mac_store_mfs_travel_mfs_and_unlock (ctx, sta->rx_llid[i],
- travel, user);
+ else
+ arch_dsr_unlock ();
}
blk_release (sta);
}
@@ -484,6 +545,7 @@ mac_store_sta_add_ (mac_store_t *ctx, uint tei __FL)
sta->mme[i] = NULL;
}
sta->rx_llid = NULL;
+ sta->rx_llid_max = 0;
/* Done, ready to be used (order is important). */
arch_reorder_barrier ();
ctx->sta[tei] = sta;