]> rtime.felk.cvut.cz Git - l4.git/blobdiff - kernel/fiasco/src/kern/dirq_io_apic.cpp
Inital import
[l4.git] / kernel / fiasco / src / kern / dirq_io_apic.cpp
diff --git a/kernel/fiasco/src/kern/dirq_io_apic.cpp b/kernel/fiasco/src/kern/dirq_io_apic.cpp
new file mode 100644 (file)
index 0000000..5b15a42
--- /dev/null
@@ -0,0 +1,217 @@
+INTERFACE:
+
+#include "dirq_pic_pin.h"
+#include "initcalls.h"
+
+class Dirq_io_apic : public Dirq_pic_pin
+{
+protected:
+  class Chip : public Dirq_pic_pin::Chip
+  {
+  public:
+    bool alloc(Irq_base *irq, unsigned irqnum);
+    void setup(Irq_base *irq, unsigned irqnum);
+    unsigned legacy_override(unsigned irq);
+    unsigned nr_irqs() const;
+    void disable_irq(unsigned irqnum);
+  };
+};
+
+
+
+IMPLEMENTATION:
+
+#include "apic.h"
+#include "io_apic.h"
+#include "receiver.h"
+#include "idt.h"
+#include "irq.h"
+
+enum
+{
+  Default_mode = Irq::Trigger_edge | Irq::Polarity_high,
+  //Default_mode = Irq::Trigger_level | Irq::Polarity_high,
+};
+
+
+IMPLEMENT
+unsigned
+Dirq_io_apic::Chip::legacy_override(unsigned irq)
+{
+  return Io_apic::legacy_override(irq);
+}
+
+
+
+IMPLEMENT
+unsigned
+Dirq_io_apic::Chip::nr_irqs() const
+{ return Io_apic::nr_irqs(); }
+
+
+IMPLEMENT
+void
+Dirq_io_apic::Chip::setup(Irq_base *irq, unsigned irqnum)
+{
+  //irq->pin()->set_mode(Default_mode);
+  if (irq->pin()->get_mode() & Irq::Trigger_level)
+    irq->pin()->replace<Pin_io_apic_level>(irqnum);
+  else
+    irq->pin()->replace<Pin_io_apic_edge>(irqnum);
+}
+
+IMPLEMENT
+bool
+Dirq_io_apic::Chip::alloc(Irq_base *irq, unsigned irqnum)
+{
+  if (!Dirq_pic_pin::Chip::alloc(irq, irqnum))
+    return false;
+
+  Io_apic_entry e = Io_apic::apic()->read_entry(irqnum);
+  e.vector(vector(irqnum));
+  Io_apic::apic()->write_entry(irqnum, e);
+  return true;
+}
+
+IMPLEMENT
+void
+Dirq_io_apic::Chip::disable_irq(unsigned vector)
+{
+  extern char entry_int_apic_ignore[];
+  Idt::set_entry(vector, Address(&entry_int_apic_ignore), false);
+}
+
+static inline
+Mword to_io_apic_trigger(unsigned mode)
+{
+  return (mode & Irq::Trigger_level)
+            ? Io_apic_entry::Level
+            : Io_apic_entry::Edge;
+}
+
+static inline
+Mword to_io_apic_polarity(unsigned mode)
+{
+  return (mode & Irq::Polarity_low)
+             ? Io_apic_entry::Low_active
+             : Io_apic_entry::High_active;
+}
+
+class Pin_io_apic_level : public Dirq_pic_pin
+{
+public:
+  explicit Pin_io_apic_level(unsigned irq) : Dirq_pic_pin(irq) {}
+};
+
+class Pin_io_apic_edge : public Pin_io_apic_level
+{
+public:
+  explicit Pin_io_apic_edge(unsigned irq) : Pin_io_apic_level(irq) {}
+};
+
+
+
+PUBLIC
+void
+Pin_io_apic_level::disable()
+{
+  extern char entry_int_apic_ignore[];
+  unsigned vector = this->vector();
+  Idt::set_entry(vector, Address(&entry_int_apic_ignore), false);
+  disable_vector();
+}
+
+PUBLIC void
+Pin_io_apic_edge::do_mask_and_ack()
+{
+  assert (cpu_lock.test());
+  Apic::irq_ack();
+}
+
+
+PUBLIC void
+Pin_io_apic_edge::do_set_mode(unsigned mode)
+{
+  Io_apic_entry e = Io_apic::apic()->read_entry(irq());
+  e.polarity(to_io_apic_polarity(mode));
+  e.trigger(to_io_apic_trigger(mode));
+  Io_apic::apic()->write_entry(irq(), e);
+  if (mode & Irq::Trigger_level)
+    new (this) Pin_io_apic_level(irq());
+}
+
+
+PUBLIC void
+Pin_io_apic_level::do_mask()
+{
+  assert (cpu_lock.test());
+  Io_apic::mask(irq());
+}
+
+
+PUBLIC
+void
+Pin_io_apic_level::ack()
+{
+  assert (cpu_lock.test());
+  Apic::irq_ack();
+}
+
+
+
+PUBLIC void
+Pin_io_apic_level::do_mask_and_ack()
+{
+  assert (cpu_lock.test());
+  __mask();
+  Io_apic::mask(irq());
+  Apic::irq_ack();
+}
+
+
+PUBLIC void
+Pin_io_apic_level::do_unmask()
+{
+  assert (cpu_lock.test());
+  Io_apic::unmask(irq());
+}
+
+PUBLIC void
+Pin_io_apic_level::set_cpu(unsigned cpu)
+{
+  Io_apic::set_dest(irq(), Cpu::cpus.cpu(cpu).phys_id());
+}
+
+
+PUBLIC void
+Pin_io_apic_level::do_set_mode(unsigned mode)
+{
+  Io_apic_entry e = Io_apic::apic()->read_entry(irq());
+  e.polarity(to_io_apic_polarity(mode));
+  e.trigger(to_io_apic_trigger(mode));
+  Io_apic::apic()->write_entry(irq(), e);
+  if (!(mode & Irq::Trigger_level))
+    new (this) Pin_io_apic_edge(irq());
+}
+
+
+PUBLIC static FIASCO_INIT
+void
+Dirq_io_apic::init()
+{
+  static Chip _ia;
+  Irq_chip::hw_chip = &_ia;
+}
+
+// --------------------------------------------------------------------------
+IMPLEMENTATION [debug]:
+
+PUBLIC
+char const *
+Pin_io_apic_level::pin_type() const
+{ return "HW IRQ (IOAPIC level)"; }
+
+PUBLIC
+char const *
+Pin_io_apic_edge::pin_type() const
+{ return "HW IRQ (IOAPIC edge)"; }