]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/arm/gic.cpp
update
[l4.git] / kernel / fiasco / src / kern / arm / gic.cpp
index c092e7d3a8cab4754973f168fd83f7e34c48ac3b..d7b0631fff04dccddf1e894e284e6fb199193b35 100644 (file)
@@ -1,23 +1,26 @@
 INTERFACE [arm && pic_gic]:
 
 #include "kmem.h"
-#include "irq_chip.h"
-#include "irq_pin.h"
+#include "irq_chip_generic.h"
 
 
-class Gic
+class Gic : public Irq_chip_gen
 {
 private:
   Address _cpu_base;
   Address _dist_base;
 
+public:
   enum
   {
     DIST_CTRL         = 0x000,
     DIST_CTR          = 0x004,
     DIST_IRQ_SEC      = 0x080,
+    GICD_IGROUPR      = DIST_IRQ_SEC, // new name
     DIST_ENABLE_SET   = 0x100,
     DIST_ENABLE_CLEAR = 0x180,
+    DIST_SET_PENDING  = 0x200,
+    DIST_CLR_PENDING  = 0x280,
     DIST_PRI          = 0x400,
     DIST_TARGET       = 0x800,
     DIST_CONFIG       = 0xc00,
@@ -40,8 +43,10 @@ private:
     MXC_TZIC_CTRL_NSEN       = 1 << 16,
     MXC_TZIC_CTRL_NSENMASK   = 1 << 31,
 
-    CPU_CTRL_ENABLE          = 1,
-    CPU_CTRL_USE_FIQ_FOR_SEC = 8,
+    CPU_CTRL_ENABLE_GRP0     = 1 << 0,
+    CPU_CTRL_ENABLE          = CPU_CTRL_ENABLE_GRP0,
+    CPU_CTRL_ENABLE_GRP1     = 1 << 1,
+    CPU_CTRL_USE_FIQ_FOR_SEC = 1 << 3,
   };
 
 };
@@ -57,65 +62,32 @@ INTERFACE [arm && pic_gic && !pic_gic_mxc_tzic]:
 EXTENSION class Gic { enum { Config_mxc_tzic = 0 }; };
 
 // ------------------------------------------------------------------------
-INTERFACE [arm && tz]:
-
-EXTENSION class Gic { enum { Config_tz = 1 }; };
-
-// ------------------------------------------------------------------------
-INTERFACE [arm && !tz]:
+INTERFACE [arm && arm_em_tz]:
 
-EXTENSION class Gic { enum { Config_tz = 0 }; };
+EXTENSION class Gic { enum { Config_tz_sec = 1 }; };
 
 // ------------------------------------------------------------------------
-INTERFACE [arm && pic_gic]:
-
-class Gic_pin : public Irq_pin
-{
-public:
-  Gic_pin(unsigned gic_idx, unsigned irq)
-  { payload()[0] = (gic_idx << 16) | irq; }
-
-  unsigned irq() const { return payload()[0] & 0xffff; }
-  Gic *gic() const { return &_gic[payload()[0] >> 16]; }
-
-  static Gic _gic[];
-};
-
-class Gic_cascade_pin : public Gic_pin
-{
-public:
-  Gic_cascade_pin(unsigned gic_idx, unsigned irq)
-    : Gic_pin(gic_idx, irq) {}
-};
+INTERFACE [arm && !arm_em_tz]:
 
-class Gic_cascade_irq : public Irq_base
-{
-public:
-  explicit Gic_cascade_irq(Gic *child_gic, Unsigned32 irq_offset)
-    : _child_gic(child_gic), _irq_offset(irq_offset) {}
+EXTENSION class Gic { enum { Config_tz_sec = 0 }; };
 
-  Unsigned32 irq_offset() const { return _irq_offset; }
-  Gic *child_gic() const { return _child_gic; }
-private:
-  Gic *_child_gic;
-  Unsigned32 _irq_offset;
-};
 
 //-------------------------------------------------------------------
 IMPLEMENTATION [arm && pic_gic]:
 
+#include <cassert>
 #include <cstring>
 #include <cstdio>
 
+#include "cascade_irq.h"
 #include "io.h"
-#include "irq.h"
 #include "irq_chip_generic.h"
 #include "panic.h"
-#include "vkey.h"
+#include "processor.h"
 
 PUBLIC inline NEEDS["io.h"]
 unsigned
-Gic::nr_irqs()
+Gic::hw_nr_irqs()
 { return ((Io::read<Mword>(_dist_base + DIST_CTR) & 0x1f) + 1) * 32; }
 
 PUBLIC inline NEEDS["io.h"]
@@ -126,57 +98,104 @@ Gic::has_sec_ext()
 PUBLIC inline
 void Gic::softint_cpu(unsigned callmap, unsigned m)
 {
-  Io::write<Mword>((callmap & 0xff) << 16 | m, _dist_base + DIST_SOFTINT);
+  Io::write<Mword>(((callmap & 0xff) << 16) | m, _dist_base + DIST_SOFTINT);
 }
 
 PUBLIC inline
 void Gic::softint_bcast(unsigned m)
-{ Io::write<Mword>(1 << 24 | m, _dist_base + DIST_SOFTINT); }
+{ Io::write<Mword>((1 << 24) | m, _dist_base + DIST_SOFTINT); }
 
-PUBLIC
+PRIVATE
 void
-Gic::init_ap()
+Gic::cpu_init()
 {
-  Io::write<Mword>(CPU_CTRL_ENABLE, _cpu_base + CPU_CTRL);
+  Io::write<Mword>(0, _cpu_base + CPU_CTRL);
+
+  Io::write<Mword>(0xffffffff, _dist_base + DIST_ENABLE_CLEAR);
+  if (Config_tz_sec)
+    {
+      Io::write<Mword>(0x00000f00, _dist_base + DIST_ENABLE_SET);
+      Io::write<Mword>(0xfffff0ff, _dist_base + GICD_IGROUPR);
+    }
+  else
+    {
+      Io::write<Mword>(0x0000001e, _dist_base + DIST_ENABLE_SET);
+      Io::write<Mword>(0, _dist_base + GICD_IGROUPR);
+    }
+
+  Io::write<Mword>(0xffffffff, _dist_base + DIST_CLR_PENDING);
+
+  Io::write<Mword>(0xffffffff, _dist_base + 0x380); // clear active
+  Io::write<Mword>(0xffffffff, _dist_base + 0xf10); // sgi pending clear
+  Io::write<Mword>(0xffffffff, _dist_base + 0xf14); // sgi pending clear
+  Io::write<Mword>(0xffffffff, _dist_base + 0xf18); // sgi pending clear
+  Io::write<Mword>(0xffffffff, _dist_base + 0xf1c); // sgi pending clear
+
+  for (unsigned i = 0; i < 32; i += 4)
+    Io::write<Mword>(0xa0a0a0a0, _dist_base + DIST_PRI + i);
+
+  if (Config_tz_sec)
+    Io::write<Mword>(0x40404040, _dist_base + DIST_PRI + 8);
+
+  Io::write<Mword>(CPU_CTRL_ENABLE | (Config_tz_sec ? CPU_CTRL_USE_FIQ_FOR_SEC : 0), _cpu_base + CPU_CTRL);
   Io::write<Mword>(0xf0, _cpu_base + CPU_PRIMASK);
 }
 
 PUBLIC
 void
-Gic::init(Address cpu_base, Address dist_base)
+Gic::init_ap()
 {
-  _cpu_base = cpu_base;
-  _dist_base = dist_base;
+  cpu_init();
+}
 
-  Io::write<Mword>(0, _dist_base + DIST_CTRL);
+PUBLIC
+unsigned
+Gic::init(bool primary_gic, int nr_irqs_override = -1)
+{
+  if (!primary_gic)
+    {
+      cpu_init();
+      return 0;
+    }
 
-  unsigned num = nr_irqs();
-  printf("Number of IRQs available at this GIC: %d\n", num);
+  Io::write<Mword>(0, _dist_base + DIST_CTRL);
 
-  unsigned int intmask = 1 << Proc::cpu_id();
-  intmask |= intmask << 8;
-  intmask |= intmask << 16;
+  unsigned num = hw_nr_irqs();
+  if (nr_irqs_override != -1)
+    num = nr_irqs_override;
 
   if (!Config_mxc_tzic)
     {
+      unsigned int intmask = 1U << cxx::int_value<Cpu_phys_id>(Proc::cpu_id());
+      intmask |= intmask << 8;
+      intmask |= intmask << 16;
+
       for (unsigned i = 32; i < num; i += 16)
         Io::write<Mword>(0, _dist_base + DIST_CONFIG + i * 4 / 16);
       for (unsigned i = 32; i < num; i += 4)
         Io::write<Mword>(intmask, _dist_base + DIST_TARGET + i);
     }
-  for (unsigned i = 0; i < num; i += 4)
+
+  for (unsigned i = 32; i < num; i += 4)
     Io::write<Mword>(0xa0a0a0a0, _dist_base + DIST_PRI + i);
-  for (unsigned i = 0; i < num; i += 32)
+
+  for (unsigned i = 32; i < num; i += 32)
     Io::write<Mword>(0xffffffff, _dist_base + DIST_ENABLE_CLEAR + i * 4 / 32);
 
-  if (Config_mxc_tzic && !Config_tz)
-    for (unsigned i = 0; i < num; i += 32)
-      Io::write<Mword>(0xffffffff, _dist_base + DIST_IRQ_SEC + i * 4 / 32);
+  Mword v = 0;
+  if (Config_tz_sec || Config_mxc_tzic)
+    v = 0xffffffff;
+
+  for (unsigned i = 32; i < num; i += 32)
+    Io::write<Mword>(v, _dist_base + GICD_IGROUPR + i / 8);
 
   Mword dist_enable = DIST_CTRL_ENABLE;
-  if (Config_mxc_tzic && !Config_tz)
+  if (Config_mxc_tzic && !Config_tz_sec)
     dist_enable |= MXC_TZIC_CTRL_NSEN | MXC_TZIC_CTRL_NSENMASK;
 
+  for (unsigned i = 0; i < num; ++i)
+    set_cpu(i, Cpu_number(0));
+
   Io::write<Mword>(dist_enable, _dist_base + DIST_CTRL);
 
   if (Config_mxc_tzic)
@@ -185,12 +204,31 @@ Gic::init(Address cpu_base, Address dist_base)
       Io::write<Mword>(0xf0, _dist_base + MXC_TZIC_PRIOMASK);
     }
   else
-    {
-      Io::write<Mword>(CPU_CTRL_ENABLE, _cpu_base + CPU_CTRL);
-      Io::write<Mword>(0xf0, _cpu_base + CPU_PRIMASK);
-    }
+    cpu_init();
+
+  return num;
+}
+
+PUBLIC
+Gic::Gic(Address cpu_base, Address dist_base, int nr_irqs_override = -1)
+  : _cpu_base(cpu_base), _dist_base(dist_base)
+{
+  unsigned num = init(true, nr_irqs_override);
+
+  printf("Number of IRQs available at this GIC: %d\n", num);
 
-  //enable_tz_support();
+  Irq_chip_gen::init(num);
+}
+
+/**
+ * \brief Create a GIC device that is a physical alias for the
+ *        master GIC.
+ */
+PUBLIC inline
+Gic::Gic(Address cpu_base, Address dist_base, Gic *master_mapping)
+  : _cpu_base(cpu_base), _dist_base(dist_base)
+{
+  Irq_chip_gen::init(master_mapping->nr_irqs());
 }
 
 PUBLIC inline NEEDS["io.h"]
@@ -201,8 +239,8 @@ PUBLIC inline NEEDS["io.h"]
 void Gic::enable_locked(unsigned irq, unsigned /*prio*/)
 { Io::write<Mword>(1 << (irq % 32), _dist_base + DIST_ENABLE_SET + (irq / 32) * 4); }
 
-PUBLIC inline NEEDS [Gic::enable_locked]
-void Gic::acknowledge_locked( unsigned irq )
+PUBLIC inline
+void Gic::acknowledge_locked(unsigned irq)
 {
   if (!Config_mxc_tzic)
     Io::write<Mword>(irq, _cpu_base + CPU_EOI);
@@ -210,85 +248,113 @@ void Gic::acknowledge_locked( unsigned irq )
 
 PUBLIC
 void
-Gic_pin::unbind_irq()
+Gic::mask(Mword pin)
 {
-  mask();
-  disable();
-  Irq_chip::hw_chip->free(Irq::self(this), irq());
-  replace<Sw_irq_pin>();
+  assert (cpu_lock.test());
+  disable_locked(pin);
 }
 
 PUBLIC
 void
-Gic_pin::do_mask()
+Gic::mask_and_ack(Mword pin)
 {
   assert (cpu_lock.test());
-  gic()->disable_locked(irq());
+  disable_locked(pin);
+  acknowledge_locked(pin);
 }
 
 PUBLIC
 void
-Gic_pin::do_mask_and_ack()
+Gic::ack(Mword pin)
 {
-  assert (cpu_lock.test());
-  __mask();
-  gic()->disable_locked(irq());
-  gic()->acknowledge_locked(irq());
+  acknowledge_locked(pin);
 }
 
+
 PUBLIC
 void
-Gic_pin::ack()
+Gic::unmask(Mword pin)
 {
-  gic()->acknowledge_locked(irq());
+  assert (cpu_lock.test());
+  enable_locked(pin, 0xa);
 }
 
+PUBLIC
+int
+Gic::set_mode(Mword, Mode)
+{
+  return 0;
+}
 
 PUBLIC
+bool
+Gic::is_edge_triggered(Mword) const
+{ return false; }
+
+PUBLIC inline
 void
-Gic_pin::do_unmask()
+Gic::hit(Upstream_irq const *u)
 {
-  assert (cpu_lock.test());
-  gic()->enable_locked(irq(), 0xa);
+  Unsigned32 num = pending();
+  if (EXPECT_FALSE(num == 0x3ff))
+    return;
+
+  handle_irq<Gic>(num, u);
 }
 
-PUBLIC
+PUBLIC static
 void
-Gic_pin::do_set_mode(unsigned)
-{}
+Gic::cascade_hit(Irq_base *_self, Upstream_irq const *u)
+{
+  // this function calls some virtual functions that might be
+  // ironed out
+  Cascade_irq *self = nonull_static_cast<Cascade_irq*>(_self);
+  Gic *gic = nonull_static_cast<Gic*>(self->child());
+  Upstream_irq ui(self, u);
+  gic->hit(&ui);
+}
+
+//-------------------------------------------------------------------
+IMPLEMENTATION [arm && arm_em_tz]:
 
 PUBLIC
 bool
-Gic_pin::check_debug_irq()
+Gic::alloc(Irq_base *irq, Mword pin)
 {
-  return !Vkey::check_(irq());
-}
+  if (Irq_chip_gen::alloc(irq, pin))
+    {
+      printf("GIC: Switching IRQ %ld to secure\n", pin);
 
+      unsigned shift = (pin & 3) * 8;
 
-PUBLIC static inline
-Gic_cascade_irq *
-Gic_cascade_irq::self(Irq_pin const *pin)
-{
-#define MYoffsetof(TYPE, MEMBER) (((size_t) &((TYPE *)10)->MEMBER) - 10)
-  return reinterpret_cast<Gic_cascade_irq*>(reinterpret_cast<Mword>(pin)
-                - MYoffsetof(Gic_cascade_irq, _pin));
-#undef MYoffsetof
+      if (pin < 32)
+        {
+          assert(((Io::read<Mword>(_dist_base + GICD_IGROUPR) >> pin) & 1) == 0);
+          assert(((Io::read<Mword>(_dist_base + DIST_PRI + (pin & ~3)) >> shift) & 0xff) == 0x40);
+        }
+      else
+        {
+          Io::clear<Mword>(1UL << (pin & 0x1f),
+                           _dist_base + GICD_IGROUPR + (pin & ~0x1f) / 8);
 
+          Io::modify<Mword>(0x40 << shift, 0xff << shift,
+                            _dist_base + DIST_PRI + (pin & ~3));
+        }
+      return true;
+    }
+  return false;
 }
 
 PUBLIC
 void
-Gic_cascade_irq::hit()
+Gic::set_pending_irq(unsigned idx, Unsigned32 val)
 {
-  Unsigned32 num = child_gic()->pending();
-  if (num == 0x3ff)
-    return;
-
-  Irq *i = nonull_static_cast<Irq*>(Irq_chip_gen::lookup(num + irq_offset()));
-  i->hit();
-
-  Gic_pin *gp = static_cast<Gic_pin*>(pin());
-  gp->gic()->acknowledge_locked(gp->irq());
+  if (idx < 32)
+    {
+      Address o = _dist_base + idx * 4;
+      Io::write<Mword>(val & Io::read<Mword>(o + GICD_IGROUPR),
+                       o + DIST_SET_PENDING);
+    }
 }
 
 //-------------------------------------------------------------------
@@ -296,7 +362,7 @@ IMPLEMENTATION [arm && !mp && pic_gic]:
 
 PUBLIC
 void
-Gic_pin::set_cpu(unsigned)
+Gic::set_cpu(Mword, Cpu_number)
 {}
 
 PUBLIC inline NEEDS["io.h"]
@@ -336,61 +402,22 @@ Unsigned32 Gic::pending()
 
 PUBLIC inline NEEDS["cpu.h"]
 void
-Gic::set_cpu(unsigned irq, unsigned cpu)
+Gic::set_cpu(Mword pin, Cpu_number cpu)
 {
-  Mword reg = _dist_base + DIST_TARGET + (irq & ~3);
+  Mword reg = _dist_base + DIST_TARGET + (pin & ~3);
   Mword val = Io::read<Mword>(reg);
 
-  int shift = (irq % 4) * 8;
-  val = (val & ~(0xf << shift)) | (1 << (Cpu::cpus.cpu(cpu).phys_id() + shift));
+  int shift = (pin % 4) * 8;
+  unsigned pcpu = cxx::int_value<Cpu_phys_id>(Cpu::cpus.cpu(cpu).phys_id());
+  val = (val & ~(0xf << shift)) | (1 << (pcpu + shift));
 
   Io::write<Mword>(val, reg);
 }
 
-PUBLIC
-void
-Gic_pin::set_cpu(unsigned cpu)
-{
-  gic()->set_cpu(irq(), cpu);
-}
-
-//-------------------------------------------------------------------
-IMPLEMENTATION [arm && pic_gic && tz]:
-
-#if 0
-PRIVATE
-void
-Gic::set_irq_nonsecure(unsigned irqnum)
-{
-  Io::set<Mword>(1 << (irqnum % 32),
-                 _dist_base + DIST_IRQ_SEC + ((irqnum & ~31) / 8));
-}
-#endif
-
-PUBLIC inline NEEDS[<cstdio>]
-void
-Gic::enable_tz_support()
-{
-  if (has_sec_ext())
-    printf("GIC:Has security extension\n");
-
-  printf("GIC: Signal secure Interrupts as FIQs!\n");
-  Io::write<Mword>(CPU_CTRL_ENABLE | CPU_CTRL_USE_FIQ_FOR_SEC,
-                   _cpu_base + CPU_CTRL);
-}
-
-//-------------------------------------------------------------------
-IMPLEMENTATION [arm && pic_gic && !tz]:
-
-PUBLIC inline
-void
-Gic::enable_tz_support()
-{}
-
 //---------------------------------------------------------------------------
 IMPLEMENTATION [debug]:
 
 PUBLIC
 char const *
-Gic_pin::pin_type() const
-{ return "HW GIC IRQ"; }
+Gic::chip_type() const
+{ return "GIC"; }