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,
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,
};
};
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"]
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)
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"]
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);
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);
+ }
}
//-------------------------------------------------------------------
PUBLIC
void
-Gic_pin::set_cpu(unsigned)
+Gic::set_cpu(Mword, Cpu_number)
{}
PUBLIC inline NEEDS["io.h"]
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"; }