dev-arm: Add a GIC interrupt adaptor
authorAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 23 Mar 2017 18:49:57 +0000 (18:49 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 7 Jun 2018 12:36:44 +0000 (12:36 +0000)
Add GIC-based interrupt adaptor implementations that support PPI
(ArmPPI) and SPI (ArmSPI) delivery. In addition to being useful for
"normal" memory-mapped devices, the PPI adaptor makes it possible to
use the same device model to generate both PPIs and SPIs (e.g., the
PMU).

Change-Id: I73d6591c168040faef2443430c4f1da10c387a2a
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/2521
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
src/dev/arm/Gic.py
src/dev/arm/base_gic.cc
src/dev/arm/base_gic.hh

index bc7794af7ad0af440f2e4dd979f7511f77a8a659..5f756639e269d7e7f5b7538372b86f1d6e41a686 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2013 ARM Limited
+# Copyright (c) 2012-2013, 2017-2018 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -49,6 +49,23 @@ class BaseGic(PioDevice):
 
     platform = Param.Platform(Parent.any, "Platform this device is part of.")
 
+class ArmInterruptPin(SimObject):
+    type = 'ArmInterruptPin'
+    cxx_header = "dev/arm/base_gic.hh"
+    abstract = True
+
+    platform = Param.Platform(Parent.any, "Platform with interrupt controller")
+    num = Param.UInt32("Interrupt number in GIC")
+
+class ArmSPI(ArmInterruptPin):
+    type = 'ArmSPI'
+    cxx_header = "dev/arm/base_gic.hh"
+
+class ArmPPI(ArmInterruptPin):
+    type = 'ArmPPI'
+    cxx_header = "dev/arm/base_gic.hh"
+
+
 class Pl390(BaseGic):
     type = 'Pl390'
     cxx_header = "dev/arm/gic_pl390.hh"
index ece8352d3644f39c2eada0a8947900b8bf092dd3..65754d0184dafcb17e401ff6b7df33b960198696 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
 
 #include "dev/arm/base_gic.hh"
 
+#include "cpu/thread_context.hh"
 #include "dev/arm/realview.hh"
+#include "params/ArmInterruptPin.hh"
+#include "params/ArmPPI.hh"
+#include "params/ArmSPI.hh"
 #include "params/BaseGic.hh"
 
 BaseGic::BaseGic(const Params *p)
@@ -65,3 +69,79 @@ BaseGic::params() const
 {
     return dynamic_cast<const Params *>(_params);
 }
+
+
+ArmInterruptPin::ArmInterruptPin(const ArmInterruptPinParams *p)
+    : SimObject(p),
+      threadContext(nullptr),
+      platform(dynamic_cast<RealView*>(p->platform)),
+      intNum(p->num)
+{
+    fatal_if(!platform, "Interrupt not connected to a RealView platform");
+}
+
+void
+ArmInterruptPin::setThreadContext(ThreadContext *tc)
+{
+    panic_if(threadContext,
+             "InterruptLine::setThreadContext called twice\n");
+
+    threadContext = tc;
+}
+
+ContextID
+ArmInterruptPin::targetContext() const
+{
+    panic_if(!threadContext, "Per-context interrupt triggered without a " \
+             "call to InterruptLine::setThreadContext.\n");
+    return threadContext->contextId();
+}
+
+
+
+ArmSPI::ArmSPI(const ArmSPIParams *p)
+    : ArmInterruptPin(p)
+{
+}
+
+void
+ArmSPI::raise()
+{
+    platform->gic->sendInt(intNum);
+}
+
+void
+ArmSPI::clear()
+{
+    platform->gic->clearInt(intNum);
+}
+
+ArmPPI::ArmPPI(const ArmPPIParams *p)
+    : ArmInterruptPin(p)
+{
+}
+
+void
+ArmPPI::raise()
+{
+    platform->gic->sendPPInt(intNum, targetContext());
+}
+
+void
+ArmPPI::clear()
+{
+    platform->gic->clearPPInt(intNum, targetContext());
+}
+
+
+ArmSPI *
+ArmSPIParams::create()
+{
+    return new ArmSPI(this);
+}
+
+ArmPPI *
+ArmPPIParams::create()
+{
+    return new ArmPPI(this);
+}
index cd16c0362826b1cb94cd45f64a6b7e62f31b1330..73d73e471494589896a85a978544cb7a022c22b5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, 2017 ARM Limited
+ * Copyright (c) 2012-2013, 2017-2018 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
 #include "dev/io_device.hh"
 
 class Platform;
+class RealView;
+class ThreadContext;
+
+struct ArmInterruptPinParams;
+struct ArmPPIParams;
+struct ArmSPIParams;
+struct BaseGicParams;
 
 class BaseGic :  public PioDevice
 {
   public:
-    typedef struct BaseGicParams Params;
+    typedef BaseGicParams Params;
 
     BaseGic(const Params *p);
     virtual ~BaseGic();
@@ -103,4 +110,67 @@ class BaseGicRegisters
     virtual void writeCpu(ContextID ctx, Addr daddr, uint32_t data) = 0;
 };
 
+/**
+ * Generic representation of an Arm interrupt pin.
+ */
+class ArmInterruptPin : public SimObject
+{
+  public:
+    ArmInterruptPin(const ArmInterruptPinParams *p);
+
+  public: /* Public interface */
+    /**
+     * Set the thread context owning this interrupt.
+     *
+     * This method is used to set the thread context for interrupts
+     * that are thread/CPU-specific. Only devices that are used in
+     * such a context are expected to call this method.
+     */
+    void setThreadContext(ThreadContext *tc);
+
+    /** Signal an interrupt */
+    virtual void raise() = 0;
+    /** Clear a signalled interrupt */
+    virtual void clear() = 0;
+
+  protected:
+    /**
+     * Get the target context ID of this interrupt.
+     *
+     * @pre setThreadContext() must have been called prior to calling
+     * this method.
+     */
+    ContextID targetContext() const;
+
+    /**
+     * Pointer to the thread context that owns this interrupt in case
+     * it is a thread-/CPU-private interrupt
+     */
+    const ThreadContext *threadContext;
+
+    /** Arm platform to use for interrupt generation */
+    RealView *const platform;
+    /** Interrupt number to generate */
+    const uint32_t intNum;
+};
+
+class ArmSPI : public ArmInterruptPin
+{
+  public:
+    ArmSPI(const ArmSPIParams *p);
+
+    void raise() override;
+    void clear() override;
+};
+
+class ArmPPI : public ArmInterruptPin
+{
+  public:
+    ArmPPI(const ArmPPIParams *p);
+
+    void raise() override;
+    void clear() override;
+};
+
+
 #endif