From: Thomas Leonard <talex5@gmail.com>
To: xen-devel@lists.xenproject.org
Cc: Thomas Leonard <talex5@gmail.com>,
Dave.Scott@eu.citrix.com, anil@recoil.org,
stefano.stabellini@eu.citrix.com, samuel.thibault@ens-lyon.org
Subject: [PATCH ARM v7 10/13] mini-os: arm: interrupt controller
Date: Fri, 8 Aug 2014 16:47:39 +0100 [thread overview]
Message-ID: <1407512862-9373-11-git-send-email-talex5@gmail.com> (raw)
In-Reply-To: <1407512862-9373-1-git-send-email-talex5@gmail.com>
Based on an initial patch by Karim Raslan.
Signed-off-by: Karim Allah Ahmed <karim.allah.ahmed@gmail.com>
Signed-off-by: Thomas Leonard <talex5@gmail.com>
---
Changes since v6:
Addressed Julien Grall's comments:
- converted ?: to if
---
| 237 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 237 insertions(+)
create mode 100644 extras/mini-os/arch/arm/gic.c
--git a/extras/mini-os/arch/arm/gic.c b/extras/mini-os/arch/arm/gic.c
new file mode 100644
index 0000000..6283ed5
--- /dev/null
+++ b/extras/mini-os/arch/arm/gic.c
@@ -0,0 +1,237 @@
+// ARM GIC implementation
+
+#include <mini-os/os.h>
+#include <mini-os/hypervisor.h>
+#include <mini-os/console.h>
+#include <libfdt.h>
+
+//#define VGIC_DEBUG
+#ifdef VGIC_DEBUG
+#define DEBUG(_f, _a...) \
+ printk("MINI_OS(file=vgic.c, line=%d) " _f , __LINE__, ## _a)
+#else
+#define DEBUG(_f, _a...) ((void)0)
+#endif
+
+extern void (*IRQ_handler)(void);
+
+struct gic {
+ volatile char *gicd_base;
+ volatile char *gicc_base;
+};
+
+static struct gic gic;
+
+// Distributor Interface
+#define GICD_CTLR 0x0
+#define GICD_ISENABLER 0x100
+#define GICD_IPRIORITYR 0x400
+#define GICD_ITARGETSR 0x800
+#define GICD_ICFGR 0xC00
+
+// CPU Interface
+#define GICC_CTLR 0x0
+#define GICC_PMR 0x4
+#define GICC_IAR 0xc
+#define GICC_EOIR 0x10
+#define GICC_HPPIR 0x18
+
+#define gicd(gic, offset) ((gic)->gicd_base + (offset))
+#define gicc(gic, offset) ((gic)->gicc_base + (offset))
+
+#define REG(addr) ((uint32_t *)(addr))
+
+static inline uint32_t REG_READ32(volatile uint32_t *addr)
+{
+ uint32_t value;
+ __asm__ __volatile__("ldr %0, [%1]":"=&r"(value):"r"(addr));
+ rmb();
+ return value;
+}
+
+static inline void REG_WRITE32(volatile uint32_t *addr, unsigned int value)
+{
+ __asm__ __volatile__("str %0, [%1]"::"r"(value), "r"(addr));
+ wmb();
+}
+
+static void gic_set_priority(struct gic *gic, int irq_number, unsigned char priority)
+{
+ uint32_t value;
+ uint32_t *addr = REG(gicd(gic, GICD_IPRIORITYR)) + (irq_number >> 2);
+ value = REG_READ32(addr);
+ value &= ~(0xff << (8 * (irq_number & 0x3))); // clear old priority
+ value |= priority << (8 * (irq_number & 0x3)); // set new priority
+ REG_WRITE32(addr, value);
+}
+
+static void gic_route_interrupt(struct gic *gic, int irq_number, unsigned char cpu_set)
+{
+ uint32_t value;
+ uint32_t *addr = REG(gicd(gic, GICD_ITARGETSR)) + (irq_number >> 2);
+ value = REG_READ32(addr);
+ value &= ~(0xff << (8 * (irq_number & 0x3))); // clear old target
+ value |= cpu_set << (8 * (irq_number & 0x3)); // set new target
+ REG_WRITE32(addr, value);
+}
+
+/* When accessing the GIC registers, we can't use LDREX/STREX because it's not regular memory. */
+static __inline__ void clear_bit_non_atomic(int nr, volatile void *base)
+{
+ volatile uint32_t *tmp = base;
+ tmp[nr >> 5] &= (unsigned long)~(1 << (nr & 0x1f));
+}
+
+static __inline__ void set_bit_non_atomic(int nr, volatile void *base)
+{
+ volatile uint32_t *tmp = base;
+ tmp[nr >> 5] |= (1 << (nr & 0x1f));
+}
+
+/* Note: not thread safe (but we only support one CPU for now anyway) */
+static void gic_enable_interrupt(struct gic *gic, int irq_number,
+ unsigned char cpu_set, unsigned char level_sensitive, unsigned char ppi)
+{
+ void *set_enable_reg;
+ void *cfg_reg;
+
+ // set priority
+ gic_set_priority(gic, irq_number, 0x0);
+
+ // set target cpus for this interrupt
+ gic_route_interrupt(gic, irq_number, cpu_set);
+
+ // set level/edge triggered
+ cfg_reg = (void *)gicd(gic, GICD_ICFGR);
+ if (level_sensitive) {
+ clear_bit_non_atomic((irq_number * 2) + 1, cfg_reg);
+ } else {
+ set_bit_non_atomic((irq_number * 2) + 1, cfg_reg);
+ }
+ if (ppi)
+ clear_bit_non_atomic((irq_number * 2), cfg_reg);
+
+ wmb();
+
+ // enable forwarding interrupt from distributor to cpu interface
+ set_enable_reg = (void *)gicd(gic, GICD_ISENABLER);
+ set_bit_non_atomic(irq_number, set_enable_reg);
+ wmb();
+}
+
+static void gic_enable_interrupts(struct gic *gic)
+{
+ // Global enable forwarding interrupts from distributor to cpu interface
+ REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000001);
+
+ // Global enable signalling of interrupt from the cpu interface
+ REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000001);
+}
+
+static void gic_disable_interrupts(struct gic *gic)
+{
+ // Global disable signalling of interrupt from the cpu interface
+ REG_WRITE32(REG(gicc(gic, GICC_CTLR)), 0x00000000);
+
+ // Global disable forwarding interrupts from distributor to cpu interface
+ REG_WRITE32(REG(gicd(gic, GICD_CTLR)), 0x00000000);
+}
+
+static void gic_cpu_set_priority(struct gic *gic, char priority)
+{
+ REG_WRITE32(REG(gicc(gic, GICC_PMR)), priority & 0x000000FF);
+}
+
+static unsigned long gic_readiar(struct gic *gic) {
+ return REG_READ32(REG(gicc(gic, GICC_IAR))) & 0x000003FF; // Interrupt ID
+}
+
+static void gic_eoir(struct gic *gic, uint32_t irq) {
+ REG_WRITE32(REG(gicc(gic, GICC_EOIR)), irq & 0x000003FF);
+}
+
+//FIXME Get event_irq from dt
+#define EVENTS_IRQ 31
+#define VIRTUALTIMER_IRQ 27
+
+static void gic_handler(void) {
+ unsigned int irq = gic_readiar(&gic);
+
+ DEBUG("IRQ received : %i\n", irq);
+ switch(irq) {
+ case EVENTS_IRQ:
+ do_hypervisor_callback(NULL);
+ break;
+ case VIRTUALTIMER_IRQ:
+ /* We need to get this event to wake us up from block_domain,
+ * but we don't need to do anything special with it. */
+ break;
+ default:
+ DEBUG("Unhandled irq\n");
+ break;
+ }
+
+ DEBUG("EIRQ\n");
+
+ gic_eoir(&gic, irq);
+}
+
+void gic_init(void) {
+ gic.gicd_base = NULL;
+ int node = 0;
+ int depth = 0;
+ for (;;)
+ {
+ node = fdt_next_node(device_tree, node, &depth);
+ if (node <= 0 || depth < 0)
+ break;
+
+ if (fdt_getprop(device_tree, node, "interrupt-controller", NULL)) {
+ int len = 0;
+
+ if (fdt_node_check_compatible(device_tree, node, "arm,cortex-a15-gic") &&
+ fdt_node_check_compatible(device_tree, node, "arm,cortex-a7-gic")) {
+ printk("Skipping incompatible interrupt-controller node\n");
+ continue;
+ }
+
+ const uint64_t *reg = fdt_getprop(device_tree, node, "reg", &len);
+
+ /* We have two registers (GICC and GICD), each of which contains
+ * two parts (an address and a size), each of which is a 64-bit
+ * value (8 bytes), so we expect a length of 2 * 2 * 8 = 32.
+ * If any extra values are passed in future, we ignore them. */
+ if (reg == NULL || len < 32) {
+ printk("Bad 'reg' property: %p %d\n", reg, len);
+ continue;
+ }
+
+ gic.gicd_base = to_virt((long) fdt64_to_cpu(reg[0]));
+ gic.gicc_base = to_virt((long) fdt64_to_cpu(reg[2]));
+ printk("Found GIC: gicd_base = %p, gicc_base = %p\n", gic.gicd_base, gic.gicc_base);
+ break;
+ }
+ }
+ if (!gic.gicd_base) {
+ printk("GIC not found!\n");
+ BUG();
+ }
+ wmb();
+
+ /* Note: we could mark this as "device" memory here, but Xen will have already
+ * set it that way in the second stage translation table, so it's not necessary.
+ * See "Overlaying the memory type attribute" in the Architecture Reference Manual.
+ */
+
+ IRQ_handler = gic_handler;
+
+ gic_disable_interrupts(&gic);
+ gic_cpu_set_priority(&gic, 0xff);
+
+ /* Must call gic_enable_interrupts before enabling individual interrupts, otherwise our IRQ handler
+ * gets called endlessly with spurious interrupts. */
+ gic_enable_interrupts(&gic);
+
+ gic_enable_interrupt(&gic, EVENTS_IRQ /* interrupt number */, 0x1 /*cpu_set*/, 1 /*level_sensitive*/, 0 /* ppi */);
+ gic_enable_interrupt(&gic, VIRTUALTIMER_IRQ /* interrupt number */, 0x1 /*cpu_set*/, 1 /*level_sensitive*/, 1 /* ppi */);
+}
--
2.0.3
next prev parent reply other threads:[~2014-08-08 15:47 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-08 15:47 [PATCH ARM v7 00/13] mini-os: initial ARM support Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 01/13] mini-os: don't include lib.h from mm.h Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 02/13] mini-os: added HYPERVISOR_xsm_op Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 03/13] mini-os: move poor rand function to test.c Thomas Leonard
2014-08-08 16:37 ` Samuel Thibault
2014-08-11 7:59 ` Thomas Leonard
2014-08-11 9:29 ` Samuel Thibault
2014-08-28 15:07 ` Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 04/13] mini-os: arm: add header files Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 05/13] mini-os: arm: boot code Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 06/13] mini-os: arm: memory management Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 07/13] mini-os: arm: scheduling Thomas Leonard
2014-08-08 15:47 ` [PATCH ARM v7 08/13] mini-os: arm: events Thomas Leonard
2014-09-08 11:52 ` Ian Campbell
2014-08-08 15:47 ` [PATCH ARM v7 09/13] mini-os: arm: time Thomas Leonard
2014-09-08 10:59 ` Ian Campbell
2014-09-08 16:08 ` Thomas Leonard
2014-09-22 10:35 ` Dave Scott
2014-09-23 16:53 ` Stefano Stabellini
2014-09-26 10:01 ` Thomas Leonard
2014-10-01 11:10 ` Thomas Leonard
2014-10-01 11:10 ` Thomas Leonard
2014-10-01 11:31 ` Ian Campbell
2014-08-08 15:47 ` Thomas Leonard [this message]
2014-09-08 11:01 ` [PATCH ARM v7 10/13] mini-os: arm: interrupt controller Ian Campbell
2014-08-08 15:47 ` [PATCH ARM v7 11/13] mini-os: arm: build system Thomas Leonard
2014-09-08 11:05 ` Ian Campbell
2014-08-08 15:47 ` [PATCH ARM v7 12/13] mini-os: arm: show registers, stack and exception vector on fault Thomas Leonard
2014-09-08 11:06 ` Ian Campbell
2014-08-08 15:47 ` [PATCH ARM v7 13/13] mini-os: fixed compiling with debug=n Thomas Leonard
2014-09-08 11:08 ` Ian Campbell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1407512862-9373-11-git-send-email-talex5@gmail.com \
--to=talex5@gmail.com \
--cc=Dave.Scott@eu.citrix.com \
--cc=anil@recoil.org \
--cc=samuel.thibault@ens-lyon.org \
--cc=stefano.stabellini@eu.citrix.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).