summaryrefslogtreecommitdiff
path: root/src/kern
diff options
context:
space:
mode:
authorAli Saidi <Ali.Saidi@ARM.com>2011-03-17 19:20:20 -0500
committerAli Saidi <Ali.Saidi@ARM.com>2011-03-17 19:20:20 -0500
commitb78be240cf1c1269ed83548bf71095193487ca33 (patch)
tree6ee8630c22e3c72291bd9fb647a91d70efed332d /src/kern
parentfe3d790ac8da41e8a0b9af93510cd874585c37e7 (diff)
downloadgem5-b78be240cf1c1269ed83548bf71095193487ca33.tar.xz
ARM: Detect and skip udelay() functions in linux kernel.
This change speeds up booting, especially in MP cases, by not executing udelay() on the core but instead skipping ahead tha amount of time that is being delayed.
Diffstat (limited to 'src/kern')
-rw-r--r--src/kern/linux/events.cc25
-rw-r--r--src/kern/linux/events.hh27
2 files changed, 52 insertions, 0 deletions
diff --git a/src/kern/linux/events.cc b/src/kern/linux/events.cc
index 60aa857ac..75c2b6f7f 100644
--- a/src/kern/linux/events.cc
+++ b/src/kern/linux/events.cc
@@ -44,11 +44,13 @@
#include <sstream>
#include "base/trace.hh"
+#include "arch/utility.hh"
#include "cpu/thread_context.hh"
#include "kern/linux/events.hh"
#include "kern/linux/printk.hh"
#include "kern/system_events.hh"
#include "sim/arguments.hh"
+#include "sim/pseudo_inst.hh"
#include "sim/system.hh"
namespace Linux {
@@ -66,4 +68,27 @@ DebugPrintkEvent::process(ThreadContext *tc)
SkipFuncEvent::process(tc);
}
+void
+UDelayEvent::process(ThreadContext *tc)
+{
+ int arg_num = 0;
+
+ // Get the time in native size
+ uint64_t time = TheISA::getArgument(tc, arg_num, (uint16_t)-1, false);
+
+ // convert parameter to ns
+ if (argDivToNs)
+ time /= argDivToNs;
+
+ time *= argMultToNs;
+
+ // Convert ns to ticks
+ time *= SimClock::Int::ns;
+
+ SkipFuncEvent::process(tc);
+
+ PseudoInst::quiesceNs(tc, time);
+}
+
+
} // namespace linux
diff --git a/src/kern/linux/events.hh b/src/kern/linux/events.hh
index e36a72dde..3f5f2526f 100644
--- a/src/kern/linux/events.hh
+++ b/src/kern/linux/events.hh
@@ -44,6 +44,33 @@ class DebugPrintkEvent : public SkipFuncEvent
virtual void process(ThreadContext *xc);
};
+/** A class to skip udelay() and related calls in the kernel.
+ * This class has two additional parameters that take the argument to udelay and
+ * manipulated it to come up with ns and eventually ticks to quiesce for.
+ * See descriptions of argDivToNs and argMultToNs below.
+ */
+class UDelayEvent : public SkipFuncEvent
+{
+ private:
+ /** value to divide arg by to create ns. This is present beacues the linux
+ * kernel code sometime precomputes the first multiply that is done in
+ * udelay() if the parameter is a constant. We need to undo it so here is
+ * how. */
+ uint64_t argDivToNs;
+
+ /** value to multiple arg by to create ns. Nominally, this is 1000 to
+ * convert us to ns, but since linux can do some preprocessing of constant
+ * values something else might be required. */
+ uint64_t argMultToNs;
+
+ public:
+ UDelayEvent(PCEventQueue *q, const std::string &desc, Addr addr,
+ uint64_t mult, uint64_t div)
+ : SkipFuncEvent(q, desc, addr), argDivToNs(div), argMultToNs(mult) {}
+ virtual void process(ThreadContext *xc);
+};
+
+
}
#endif