rewrite the gic implementation, some other fix ups
[lunaix-os.git] / lunaix-os / arch / aarch64 / soc / gic / gic-common.h
diff --git a/lunaix-os/arch/aarch64/soc/gic/gic-common.h b/lunaix-os/arch/aarch64/soc/gic/gic-common.h
new file mode 100644 (file)
index 0000000..3ef0363
--- /dev/null
@@ -0,0 +1,239 @@
+#ifndef __LUNAIX_GIC_COMMON_H
+#define __LUNAIX_GIC_COMMON_H
+
+#include <lunaix/types.h>
+#include <lunaix/status.h>
+#include <hal/irq.h>
+
+#define PAD(body, name, offset)   \
+    struct { char _pad_##name[offset]; body; } compact
+
+#define PAD_STRUCT(body, name, offset)  \
+    PAD(struct body, name, offset)
+
+#define FIELD_AT(type, field, offset)   \
+    PAD(volatile type field, field, offset)
+
+#define ARRAY_AT(type, arr, offset, end)   \
+    PAD(volatile type arr[((end) - (offset)) / sizeof(type) + 1], arr, offset)
+
+
+typedef unsigned int intid_t;
+
+struct gic_pe;
+struct gic_int_class;
+
+enum gic_intkind
+{
+    GIC_INT_SGI = 0,
+    GIC_INT_PPI,
+    GIC_INT_PPI_EXT,
+    GIC_INT_LPI,
+    GIC_INT_SPI,
+    GIC_INT_SPI_EXT,
+    GIC_INT_COUNT
+};
+
+enum gic_intgrp
+{
+    GIC_INT_GROUP0,
+    GIC_INT_GROUP1_S,
+    GIC_INT_GROUP1_NS,
+};
+
+enum gic_trigger
+{
+    GIC_TRIG_LEVEL,
+    GIC_TRIG_EDGE,
+};
+
+struct gic_interrupt
+{
+    intid_t intid;
+
+    enum gic_intgrp grp;
+    enum gic_intkind kind;
+    enum gic_trigger trig;
+    int priority;
+    bool nmi;
+    bool enabled;
+
+    union {
+        u64_t raw_val;
+        struct gic_pe* pe;
+    } affinity;
+    
+    struct irq_object* irq;
+};
+#define GIC_INTR_RAW_AFF    1
+
+struct gic_int_class_ops
+{
+    int (*set_enabled)(struct gic_int_class*, intid_t, bool);
+    int (*set_prority)(struct gic_int_class*, intid_t, int);
+    int (*set_nmi)(struct gic_int_class*, intid_t, bool);
+    int (*set_route)(struct gic_int_class*,intid_t, struct gic_pe*);
+    int (*set_trigger)(struct gic_int_class*,intid_t, enum gic_trigger);
+
+    int (*retrieve)(struct gic_int_class*, struct gic_interrupt*, intid_t);
+    int (*install)(struct gic_int_class*, struct gic_interrupt*);
+    int (*delete)(struct gic_int_class*, intid_t);
+
+    int (*fire)(struct gic_int_class*, intid_t);
+};
+extern const struct gic_int_class_ops aa64_gic_fallback_ops;
+
+struct gic;
+struct gic_pe;
+struct gic_int_class
+{
+    enum gic_intkind kind;
+    
+    struct {
+        intid_t start;
+        intid_t stop;
+    } range;
+
+    struct gic_int_class_ops* ops;
+};
+
+struct gic_pe_ops
+{
+    bool (*ack_int)(struct gic_pe*);
+    int (*notify_eoi)(struct gic_pe*);
+    int (*set_priority_mask)(struct gic_pe*, int);
+};
+
+struct gic_pe
+{
+    union {
+        struct {
+            struct gic_int_class sgi;
+            struct gic_int_class ppi;
+            struct gic_int_class ppi_e;
+            struct gic_int_class lpi;
+        };
+        struct gic_int_class classes[4];
+    };
+
+    struct {
+        union {
+            intid_t active_id;
+            struct gic_interrupt active_int;
+        };
+        bool has_active_int;
+    };
+
+    void* impl;
+
+    int index;
+    int affinity;
+
+    struct gic* distr;
+    struct gic_pe_ops* ops;
+};
+
+struct gic
+{
+    int nr_cpus;
+    struct gic_pe** cores;
+
+    union {
+        struct {
+            struct gic_int_class spi;
+            struct gic_int_class spi_e;
+        };
+        struct gic_int_class classes[2];
+    };
+
+    void* impl;
+
+    struct irq_domain* domain;
+};
+
+static inline void
+gic_init_int_class(struct gic_int_class* class, 
+                   enum gic_intkind kind, intid_t start, intid_t end)
+{
+    *class = (struct gic_int_class) {
+        .range.start = start,
+        .range.stop  = end,
+        .kind = kind
+    };
+}
+
+static inline bool
+gic_valid_int_class(struct gic_int_class* class) {
+    return class->ops && (class->range.start < class->range.stop);
+}
+
+static inline void
+gic_intr_set_raw_affval(struct gic_interrupt* intr, u32_t affval)
+{
+    intr->affinity.raw_val = ((u64_t)affval << 1) | GIC_INTR_RAW_AFF;
+}
+
+static inline int
+gic_assign_intid(struct gic_int_class* class, irq_t irq)
+{
+    int err;
+    struct gic* gic;
+
+    if (!gic_valid_int_class(class)) {
+        // selected class not present or disabled
+        return ENOENT;
+    }
+
+    gic = gic_global_context_of(class);
+    err = irq_alloc_id(gic->domain, irq, 
+                        class->range.start, class->range.stop);
+
+    return err;
+}
+
+struct gic_pe*
+gic_create_pe_context(struct gic* gic, void* pe_impl);
+
+struct gic_pe*
+gic_local_context_of(struct gic_int_class* int_class);
+
+struct gic*
+gic_global_context_of(struct gic_int_class* int_class);
+
+int
+gic_get_interrupt(struct gic* gic, intid_t id, struct gic_interrupt* intr_out);
+
+struct gic*
+gic_create_context(struct device* gicdev);
+
+
+// default ops
+
+int 
+__fallback_set_enabled(struct gic_int_class* class, intid_t intid, bool en);
+
+int 
+__fallback_set_prority(struct gic_int_class* class, intid_t intid, int prio);
+
+int 
+__fallback_set_nmi(struct gic_int_class* class, intid_t intid, bool nmi);
+
+int 
+__fallback_set_route(struct gic_int_class* class, 
+                intid_t intid, struct gic_pe* target);
+
+int 
+__fallback_set_trigger(struct gic_int_class* class, 
+                  intid_t intid, enum gic_trigger trig);
+
+
+int 
+__fallback_retrieve(struct gic_int_class* class, 
+               struct gic_interrupt*, intid_t intid);
+
+int 
+__fallback_install(struct gic_int_class* class, struct gic_interrupt* gic);
+
+int 
+__fallback_delete(struct gic_int_class* class, intid_t intid);
+#endif /* __LUNAIX_GIC_COMMON_H */