All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/16] xen/arm: Add GICv3 support
@ 2014-04-15 11:17 vijay.kilari
  2014-04-15 11:17 ` [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder vijay.kilari
                   ` (15 more replies)
  0 siblings, 16 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Made changes to existing gic and vgic drivers
to make it generic and added support for GIC v3
hw version

Tested with ARM64 simulator with multicore core
and booted Dom0 kernel.

Major changes in v3:
 - Moved io.h from xen/arch/arm to xen/include/asm-arm
   and renamed as mmio.h
 - Made all the io handlers as domain specific and removed
   check handlers. Instead address and size are passed
 - Cleaned up sgi handling functions in V2 gic driver and
   made generic
 - Removed unused parameters in do_sgi call
 - VGIC driver is chosen based on GIC driver initialized
 - Implemented SGI handling for GICv3 to boot multicore
 - Missing coding style fixes
 - Rebased to remotes/origin/no_maintenance_interrupts-v6
   branch of Stephano's unstable tree

Major Changes in v2:
 - Added per domain io handler
 - Use device api to initialize gic driver
 - Avoid use of void pointer to access common data
 - Moved vgic address information data from domain.h
 - Coding style

Vijaya Kumar K (16):
  xen/arm: move io.h as mmio.h to include folder
  xen/arm: make mmio handlers domain specific
  xen/arm: make sgi handling generic
  xen/arm: remove unused parameter in do_sgi call
  xen/arm: move gic definitions to seperate file
  xen/arm: move gic lock out of gic data structure
  xen/arm: segregate and split GIC low level functionality
  arm/xen: move GIC context data structure to gic driver
  xen/arm: use device api to detect GIC version
  xen/arm: move vgic rank data to gic header file
  xen/arm: move vgic defines to vgic header file
  xen/arm: split vgic driver into generic and vgic-v2 driver
  xen/arm: Add support for GIC v3
  xen/arm: Add virtual GICv3 support
  xen/arm: Update Dom0 GIC dt node with GICv3 information
  xen/arm: add SGI handling for GICv3

 xen/arch/arm/Makefile                 |    4 +-
 xen/arch/arm/domain.c                 |    5 +
 xen/arch/arm/domain_build.c           |    9 +-
 xen/arch/arm/gic-v2.c                 |  545 ++++++++++++++++++
 xen/arch/arm/gic-v3.c                 | 1000 +++++++++++++++++++++++++++++++++
 xen/arch/arm/gic.c                    |  459 ++++-----------
 xen/arch/arm/io.c                     |   45 +-
 xen/arch/arm/io.h                     |   57 --
 xen/arch/arm/irq.c                    |    1 +
 xen/arch/arm/time.c                   |    1 +
 xen/arch/arm/traps.c                  |   11 +-
 xen/arch/arm/vgic-v2.c                |  540 ++++++++++++++++++
 xen/arch/arm/vgic-v3.c                |  914 ++++++++++++++++++++++++++++++
 xen/arch/arm/vgic.c                   |  572 ++-----------------
 xen/arch/arm/vpsci.c                  |    1 +
 xen/arch/arm/vtimer.c                 |    1 +
 xen/arch/arm/vuart.c                  |   19 +-
 xen/include/asm-arm/arm64/processor.h |   14 +
 xen/include/asm-arm/device.h          |    3 +-
 xen/include/asm-arm/domain.h          |   23 +-
 xen/include/asm-arm/gic.h             |  229 ++++----
 xen/include/asm-arm/gic_v2_defs.h     |  138 +++++
 xen/include/asm-arm/gic_v3_defs.h     |  214 +++++++
 xen/include/asm-arm/mmio.h            |   64 +++
 xen/include/asm-arm/sysregs.h         |    2 +-
 xen/include/asm-arm/vgic.h            |  110 ++++
 26 files changed, 3887 insertions(+), 1094 deletions(-)
 create mode 100644 xen/arch/arm/gic-v2.c
 create mode 100644 xen/arch/arm/gic-v3.c
 delete mode 100644 xen/arch/arm/io.h
 create mode 100644 xen/arch/arm/vgic-v2.c
 create mode 100644 xen/arch/arm/vgic-v3.c
 create mode 100644 xen/include/asm-arm/gic_v2_defs.h
 create mode 100644 xen/include/asm-arm/gic_v3_defs.h
 create mode 100644 xen/include/asm-arm/mmio.h
 create mode 100644 xen/include/asm-arm/vgic.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 107+ messages in thread

* [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 16:36   ` Julien Grall
  2014-04-23 14:16   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 02/16] xen/arm: make mmio handlers domain specific vijay.kilari
                   ` (14 subsequent siblings)
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

io.h is local to arch/arm folder. move this file as mmio.h
file to include/asm-arm folder as it might be
required for inclusion in other header files in future.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/io.c          |    3 +--
 xen/arch/arm/io.h          |   57 --------------------------------------------
 xen/arch/arm/traps.c       |    2 +-
 xen/arch/arm/vgic.c        |    2 +-
 xen/arch/arm/vuart.c       |    2 +-
 xen/include/asm-arm/mmio.h |   57 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 61 insertions(+), 62 deletions(-)

diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c
index a6db00b..ada1918 100644
--- a/xen/arch/arm/io.c
+++ b/xen/arch/arm/io.c
@@ -19,8 +19,7 @@
 #include <xen/config.h>
 #include <xen/lib.h>
 #include <asm/current.h>
-
-#include "io.h"
+#include <asm/mmio.h>
 
 static const struct mmio_handler *const mmio_handlers[] =
 {
diff --git a/xen/arch/arm/io.h b/xen/arch/arm/io.h
deleted file mode 100644
index 8d252c0..0000000
--- a/xen/arch/arm/io.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * xen/arch/arm/io.h
- *
- * ARM I/O handlers
- *
- * Copyright (c) 2011 Citrix Systems.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ARCH_ARM_IO_H__
-#define __ARCH_ARM_IO_H__
-
-#include <xen/lib.h>
-#include <asm/processor.h>
-#include <asm/regs.h>
-
-typedef struct
-{
-    struct hsr_dabt dabt;
-    vaddr_t gva;
-    paddr_t gpa;
-} mmio_info_t;
-
-typedef int (*mmio_read_t)(struct vcpu *v, mmio_info_t *info);
-typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info);
-typedef int (*mmio_check_t)(struct vcpu *v, paddr_t addr);
-
-struct mmio_handler {
-    mmio_check_t check_handler;
-    mmio_read_t read_handler;
-    mmio_write_t write_handler;
-};
-
-extern const struct mmio_handler vgic_distr_mmio_handler;
-extern const struct mmio_handler vuart_mmio_handler;
-
-extern int handle_mmio(mmio_info_t *info);
-
-#endif
-
-/*
- * Local variables:
- * mode: C
- * c-file-style: "BSD"
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index dd936be..e0184b1 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -35,9 +35,9 @@
 #include <asm/regs.h>
 #include <asm/cpregs.h>
 #include <asm/psci.h>
+#include <asm/mmio.h>
 
 #include "decode.h"
-#include "io.h"
 #include "vtimer.h"
 #include <asm/gic.h>
 
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index bd15be7..9c404fe 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -27,7 +27,7 @@
 
 #include <asm/current.h>
 
-#include "io.h"
+#include <asm/mmio.h>
 #include <asm/gic.h>
 
 #define REG(n) (n/4)
diff --git a/xen/arch/arm/vuart.c b/xen/arch/arm/vuart.c
index b9d3ced..895e5cd 100644
--- a/xen/arch/arm/vuart.c
+++ b/xen/arch/arm/vuart.c
@@ -38,9 +38,9 @@
 #include <xen/errno.h>
 #include <xen/ctype.h>
 #include <xen/serial.h>
+#include <asm/mmio.h>
 
 #include "vuart.h"
-#include "io.h"
 
 #define domain_has_vuart(d) ((d)->arch.vuart.info != NULL)
 
diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h
new file mode 100644
index 0000000..44b28a6
--- /dev/null
+++ b/xen/include/asm-arm/mmio.h
@@ -0,0 +1,57 @@
+/*
+ * xen/arch/arm/mmio.h
+ *
+ * ARM I/O handlers
+ *
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ARCH_ARM_MMIO_H__
+#define __ARCH_ARM_MMIO_H__
+
+#include <xen/lib.h>
+#include <asm/processor.h>
+#include <asm/regs.h>
+
+typedef struct
+{
+    struct hsr_dabt dabt;
+    vaddr_t gva;
+    paddr_t gpa;
+} mmio_info_t;
+
+typedef int (*mmio_read_t)(struct vcpu *v, mmio_info_t *info);
+typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info);
+typedef int (*mmio_check_t)(struct vcpu *v, paddr_t addr);
+
+struct mmio_handler {
+    mmio_check_t check_handler;
+    mmio_read_t read_handler;
+    mmio_write_t write_handler;
+};
+
+extern const struct mmio_handler vgic_distr_mmio_handler;
+extern const struct mmio_handler vuart_mmio_handler;
+
+extern int handle_mmio(mmio_info_t *info);
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 02/16] xen/arm: make mmio handlers domain specific
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
  2014-04-15 11:17 ` [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 17:07   ` Julien Grall
  2014-04-15 11:17 ` [PATCH v3 03/16] xen/arm: make sgi handling generic vijay.kilari
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

register mmio handlers at runtime and make
mmio handlers domain specific and check
handlers are removed.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/domain.c        |    3 +++
 xen/arch/arm/io.c            |   42 ++++++++++++++++++++++++++++++------------
 xen/arch/arm/vgic.c          |   16 +++++++---------
 xen/arch/arm/vuart.c         |   17 +++++++----------
 xen/include/asm-arm/domain.h |    2 ++
 xen/include/asm-arm/mmio.h   |   13 ++++++++++---
 6 files changed, 59 insertions(+), 34 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index e6ddedf..0d52457 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -521,6 +521,9 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
     share_xen_page_with_guest(
         virt_to_page(d->shared_info), d, XENSHARE_writable);
 
+    if ( (rc = domain_io_init(d)) != 0 )
+        goto fail;
+
     if ( (rc = p2m_alloc_table(d)) != 0 )
         goto fail;
 
diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c
index ada1918..1a0be89 100644
--- a/xen/arch/arm/io.c
+++ b/xen/arch/arm/io.c
@@ -18,29 +18,47 @@
 
 #include <xen/config.h>
 #include <xen/lib.h>
+#include <xen/spinlock.h>
+#include <xen/sched.h>
 #include <asm/current.h>
 #include <asm/mmio.h>
 
-static const struct mmio_handler *const mmio_handlers[] =
-{
-    &vgic_distr_mmio_handler,
-    &vuart_mmio_handler,
-};
-#define MMIO_HANDLER_NR ARRAY_SIZE(mmio_handlers)
-
 int handle_mmio(mmio_info_t *info)
 {
     struct vcpu *v = current;
     int i;
+    struct io_handler *mmio_handle = &v->domain->arch.io_handlers;
 
-    for ( i = 0; i < MMIO_HANDLER_NR; i++ )
-        if ( mmio_handlers[i]->check_handler(v, info->gpa) )
+    for ( i = 0; i < mmio_handle->num_entries; i++ )
+    {
+        if ( (info->gpa >= mmio_handle->mmio_handlers[i]->addr) &&
+              info->gpa < (mmio_handle->mmio_handlers[i]->addr + mmio_handle->mmio_handlers[i]->size) )
             return info->dabt.write ?
-                mmio_handlers[i]->write_handler(v, info) :
-                mmio_handlers[i]->read_handler(v, info);
-
+                mmio_handle->mmio_handlers[i]->write_handler(v, info) :
+                mmio_handle->mmio_handlers[i]->read_handler(v, info);
+    }
     return 0;
 }
+
+void register_mmio_handler(struct domain *d, struct mmio_handler * handle)
+{
+    struct io_handler *handler = &d->arch.io_handlers;
+
+    BUG_ON(handler->num_entries >= MAX_IO_HANDLER);
+
+    spin_lock(&handler->lock);
+    handler->mmio_handlers[handler->num_entries] = handle;
+    handler->num_entries++;
+    spin_unlock(&handler->lock);
+}
+
+int domain_io_init(struct domain *d)
+{
+   spin_lock_init(&d->arch.io_handlers.lock);
+   d->arch.io_handlers.num_entries = 0;
+   return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 9c404fe..d36058a 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -35,6 +35,8 @@
 /* Number of ranks of interrupt registers for a domain */
 #define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
 
+static struct mmio_handler vgic_distr_mmio_handler;
+
 /*
  * Rank containing GICD_<FOO><n> for GICD_<FOO> with
  * <b>-bits-per-interrupt
@@ -98,6 +100,10 @@ int domain_vgic_init(struct domain *d)
     }
     for (i=0; i<DOMAIN_NR_RANKS(d); i++)
         spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
+
+    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
+    vgic_distr_mmio_handler.size = PAGE_SIZE;
+    register_mmio_handler(d, &vgic_distr_mmio_handler);
     return 0;
 }
 
@@ -657,15 +663,7 @@ write_ignore:
     return 1;
 }
 
-static int vgic_distr_mmio_check(struct vcpu *v, paddr_t addr)
-{
-    struct domain *d = v->domain;
-
-    return (addr >= (d->arch.vgic.dbase)) && (addr < (d->arch.vgic.dbase + PAGE_SIZE));
-}
-
-const struct mmio_handler vgic_distr_mmio_handler = {
-    .check_handler = vgic_distr_mmio_check,
+static struct mmio_handler vgic_distr_mmio_handler = {
     .read_handler  = vgic_distr_mmio_read,
     .write_handler = vgic_distr_mmio_write,
 };
diff --git a/xen/arch/arm/vuart.c b/xen/arch/arm/vuart.c
index 895e5cd..f43f2e5 100644
--- a/xen/arch/arm/vuart.c
+++ b/xen/arch/arm/vuart.c
@@ -44,6 +44,8 @@
 
 #define domain_has_vuart(d) ((d)->arch.vuart.info != NULL)
 
+static struct mmio_handler vuart_mmio_handler;
+
 int domain_vuart_init(struct domain *d)
 {
     ASSERT( !d->domain_id );
@@ -59,6 +61,10 @@ int domain_vuart_init(struct domain *d)
     if ( !d->arch.vuart.buf )
         return -ENOMEM;
 
+    vuart_mmio_handler.addr = d->arch.vuart.info->base_addr;
+    vuart_mmio_handler.size = d->arch.vuart.info->size;
+    register_mmio_handler(d, &vuart_mmio_handler);
+
     return 0;
 }
 
@@ -92,14 +98,6 @@ static void vuart_print_char(struct vcpu *v, char c)
     spin_unlock(&uart->lock);
 }
 
-static int vuart_mmio_check(struct vcpu *v, paddr_t addr)
-{
-    const struct vuart_info *info = v->domain->arch.vuart.info;
-
-    return (domain_has_vuart(v->domain) && addr >= info->base_addr &&
-            addr <= (info->base_addr + info->size));
-}
-
 static int vuart_mmio_read(struct vcpu *v, mmio_info_t *info)
 {
     struct domain *d = v->domain;
@@ -133,8 +131,7 @@ static int vuart_mmio_write(struct vcpu *v, mmio_info_t *info)
     return 1;
 }
 
-const struct mmio_handler vuart_mmio_handler = {
-    .check_handler = vuart_mmio_check,
+static struct mmio_handler vuart_mmio_handler = {
     .read_handler  = vuart_mmio_read,
     .write_handler = vuart_mmio_write,
 };
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 696f36c..999bbdd 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -7,6 +7,7 @@
 #include <asm/page.h>
 #include <asm/p2m.h>
 #include <asm/vfp.h>
+#include <asm/mmio.h>
 #include <public/hvm/params.h>
 #include <xen/serial.h>
 
@@ -116,6 +117,7 @@ struct arch_domain
     struct hvm_domain hvm_domain;
     xen_pfn_t *grant_table_gpfn;
 
+    struct io_handler io_handlers;
     /* Continuable domain_relinquish_resources(). */
     enum {
         RELMEM_not_started,
diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h
index 44b28a6..2bb5f5e 100644
--- a/xen/include/asm-arm/mmio.h
+++ b/xen/include/asm-arm/mmio.h
@@ -35,15 +35,22 @@ typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info);
 typedef int (*mmio_check_t)(struct vcpu *v, paddr_t addr);
 
 struct mmio_handler {
-    mmio_check_t check_handler;
+    paddr_t addr;
+    unsigned long size;
     mmio_read_t read_handler;
     mmio_write_t write_handler;
 };
 
-extern const struct mmio_handler vgic_distr_mmio_handler;
-extern const struct mmio_handler vuart_mmio_handler;
+#define MAX_IO_HANDLER  16
+struct io_handler {
+    int num_entries;
+    spinlock_t lock;
+    struct mmio_handler *mmio_handlers[MAX_IO_HANDLER];
+};
 
 extern int handle_mmio(mmio_info_t *info);
+void register_mmio_handler(struct domain *d, struct mmio_handler * handle);
+int domain_io_init(struct domain *d);
 
 #endif
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 03/16] xen/arm: make sgi handling generic
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
  2014-04-15 11:17 ` [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder vijay.kilari
  2014-04-15 11:17 ` [PATCH v3 02/16] xen/arm: make mmio handlers domain specific vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 17:51   ` Julien Grall
  2014-04-15 11:17 ` [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call vijay.kilari
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

move all the hw specific sgi handling functionality
to one function and use it.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic.c        |   36 +++++++++++++++++++++++++++---------
 xen/include/asm-arm/gic.h |    4 ++++
 2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 7faa0e9..d5cc931 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -480,21 +480,39 @@ void __init gic_init(void)
     spin_unlock(&gic.lock);
 }
 
-void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi)
+void send_sgi(const cpumask_t *online_mask, enum gic_sgi sgi, uint8_t irqmode)
 {
     unsigned int mask = 0;
+
+    switch(irqmode)
+    {
+    case SGI_TARGET_OTHERS:
+        GICD[GICD_SGIR] = GICD_SGI_TARGET_OTHERS | sgi;
+        break;
+    case SGI_TARGET_SELF:
+        GICD[GICD_SGIR] = GICD_SGI_TARGET_SELF | sgi;
+        break;
+    case SGI_TARGET_LIST:
+        mask = gic_cpu_mask(online_mask);
+        GICD[GICD_SGIR] = GICD_SGI_TARGET_LIST |
+                          (mask<<GICD_SGI_TARGET_SHIFT) | sgi;
+        break;
+    default:
+         gdprintk(XENLOG_WARNING, "Wrong sgi irq mode for sgi %x\n", sgi);
+    }
+}
+
+void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi)
+{
     cpumask_t online_mask;
 
     ASSERT(sgi < 16); /* There are only 16 SGIs */
 
     cpumask_and(&online_mask, cpumask, &cpu_online_map);
-    mask = gic_cpu_mask(&online_mask);
 
     dsb();
 
-    GICD[GICD_SGIR] = GICD_SGI_TARGET_LIST
-        | (mask<<GICD_SGI_TARGET_SHIFT)
-        | sgi;
+    send_sgi(&online_mask, sgi, SGI_TARGET_LIST);
 }
 
 void send_SGI_one(unsigned int cpu, enum gic_sgi sgi)
@@ -509,18 +527,18 @@ void send_SGI_self(enum gic_sgi sgi)
 
     dsb();
 
-    GICD[GICD_SGIR] = GICD_SGI_TARGET_SELF
-        | sgi;
+    send_sgi(cpumask_of(smp_processor_id()), sgi, SGI_TARGET_SELF);
 }
 
 void send_SGI_allbutself(enum gic_sgi sgi)
 {
+   cpumask_t all_others_mask;
    ASSERT(sgi < 16); /* There are only 16 SGIs */
 
+   cpumask_andnot(&all_others_mask, &cpu_possible_map, cpumask_of(smp_processor_id()));
    dsb();
 
-   GICD[GICD_SGIR] = GICD_SGI_TARGET_OTHERS
-       | sgi;
+   send_sgi(&all_others_mask, sgi, SGI_TARGET_OTHERS);
 }
 
 void smp_send_state_dump(unsigned int cpu)
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 5d8f7f1..d03b490 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -50,6 +50,10 @@
 #define GICD_SPENDSGIRN (0xF2C/4)
 #define GICD_ICPIDR2    (0xFE8/4)
 
+#define SGI_TARGET_LIST    0
+#define SGI_TARGET_OTHERS  1
+#define SGI_TARGET_SELF    2
+
 #define GICD_SGI_TARGET_LIST_SHIFT   (24)
 #define GICD_SGI_TARGET_LIST_MASK    (0x3UL << GICD_SGI_TARGET_LIST_SHIFT)
 #define GICD_SGI_TARGET_LIST         (0UL<<GICD_SGI_TARGET_LIST_SHIFT)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (2 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 03/16] xen/arm: make sgi handling generic vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 17:52   ` Julien Grall
  2014-04-23 14:32   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 05/16] xen/arm: move gic definitions to seperate file vijay.kilari
                   ` (11 subsequent siblings)
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

othercpu parameter in do_sgi is unused

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic.c |    5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index d5cc931..fa49049 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -936,7 +936,7 @@ out:
     return retval;
 }
 
-static void do_sgi(struct cpu_user_regs *regs, int othercpu, enum gic_sgi sgi)
+static void do_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
 {
     /* Lower the priority */
     GICC[GICC_EOIR] = sgi;
@@ -980,8 +980,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
         }
         else if (unlikely(irq < 16))
         {
-            unsigned int cpu = (intack & GICC_IA_CPU_MASK) >> GICC_IA_CPU_SHIFT;
-            do_sgi(regs, cpu, irq);
+            do_sgi(regs, irq);
         }
         else
         {
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 05/16] xen/arm: move gic definitions to seperate file
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (3 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-23 14:34   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure vijay.kilari
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Move gic v2 register definitions to separate file
so that gic.h will hold only common definitions
and helps to define gic v3 definitions.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic.c                |    1 +
 xen/arch/arm/vgic.c               |    1 +
 xen/include/asm-arm/gic.h         |  121 +------------------------------
 xen/include/asm-arm/gic_v2_defs.h |  144 +++++++++++++++++++++++++++++++++++++
 4 files changed, 149 insertions(+), 118 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index fa49049..05f2240 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -32,6 +32,7 @@
 #include <asm/domain.h>
 #include <asm/platform.h>
 
+#include <asm/gic_v2_defs.h>
 #include <asm/gic.h>
 
 /* Access to the GIC Distributor registers through the fixmap */
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index d36058a..4830b5d 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -28,6 +28,7 @@
 #include <asm/current.h>
 
 #include <asm/mmio.h>
+#include <asm/gic_v2_defs.h>
 #include <asm/gic.h>
 
 #define REG(n) (n/4)
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index d03b490..eba41ee 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -18,124 +18,6 @@
 #ifndef __ASM_ARM_GIC_H__
 #define __ASM_ARM_GIC_H__
 
-#define GICD_CTLR       (0x000/4)
-#define GICD_TYPER      (0x004/4)
-#define GICD_IIDR       (0x008/4)
-#define GICD_IGROUPR    (0x080/4)
-#define GICD_IGROUPRN   (0x0FC/4)
-#define GICD_ISENABLER  (0x100/4)
-#define GICD_ISENABLERN (0x17C/4)
-#define GICD_ICENABLER  (0x180/4)
-#define GICD_ICENABLERN (0x1fC/4)
-#define GICD_ISPENDR    (0x200/4)
-#define GICD_ISPENDRN   (0x27C/4)
-#define GICD_ICPENDR    (0x280/4)
-#define GICD_ICPENDRN   (0x2FC/4)
-#define GICD_ISACTIVER  (0x300/4)
-#define GICD_ISACTIVERN (0x37C/4)
-#define GICD_ICACTIVER  (0x380/4)
-#define GICD_ICACTIVERN (0x3FC/4)
-#define GICD_IPRIORITYR (0x400/4)
-#define GICD_IPRIORITYRN (0x7F8/4)
-#define GICD_ITARGETSR  (0x800/4)
-#define GICD_ITARGETSRN (0xBF8/4)
-#define GICD_ICFGR      (0xC00/4)
-#define GICD_ICFGRN     (0xCFC/4)
-#define GICD_NSACR      (0xE00/4)
-#define GICD_NSACRN     (0xEFC/4)
-#define GICD_SGIR       (0xF00/4)
-#define GICD_CPENDSGIR  (0xF10/4)
-#define GICD_CPENDSGIRN (0xF1C/4)
-#define GICD_SPENDSGIR  (0xF20/4)
-#define GICD_SPENDSGIRN (0xF2C/4)
-#define GICD_ICPIDR2    (0xFE8/4)
-
-#define SGI_TARGET_LIST    0
-#define SGI_TARGET_OTHERS  1
-#define SGI_TARGET_SELF    2
-
-#define GICD_SGI_TARGET_LIST_SHIFT   (24)
-#define GICD_SGI_TARGET_LIST_MASK    (0x3UL << GICD_SGI_TARGET_LIST_SHIFT)
-#define GICD_SGI_TARGET_LIST         (0UL<<GICD_SGI_TARGET_LIST_SHIFT)
-#define GICD_SGI_TARGET_OTHERS       (1UL<<GICD_SGI_TARGET_LIST_SHIFT)
-#define GICD_SGI_TARGET_SELF         (2UL<<GICD_SGI_TARGET_LIST_SHIFT)
-#define GICD_SGI_TARGET_SHIFT        (16)
-#define GICD_SGI_TARGET_MASK         (0xFFUL<<GICD_SGI_TARGET_SHIFT)
-#define GICD_SGI_GROUP1              (1UL<<15)
-#define GICD_SGI_INTID_MASK          (0xFUL)
-
-#define GICC_CTLR       (0x0000/4)
-#define GICC_PMR        (0x0004/4)
-#define GICC_BPR        (0x0008/4)
-#define GICC_IAR        (0x000C/4)
-#define GICC_EOIR       (0x0010/4)
-#define GICC_RPR        (0x0014/4)
-#define GICC_HPPIR      (0x0018/4)
-#define GICC_APR        (0x00D0/4)
-#define GICC_NSAPR      (0x00E0/4)
-#define GICC_DIR        (0x1000/4)
-
-#define GICH_HCR        (0x00/4)
-#define GICH_VTR        (0x04/4)
-#define GICH_VMCR       (0x08/4)
-#define GICH_MISR       (0x10/4)
-#define GICH_EISR0      (0x20/4)
-#define GICH_EISR1      (0x24/4)
-#define GICH_ELSR0      (0x30/4)
-#define GICH_ELSR1      (0x34/4)
-#define GICH_APR        (0xF0/4)
-#define GICH_LR         (0x100/4)
-
-/* Register bits */
-#define GICD_CTL_ENABLE 0x1
-
-#define GICD_TYPE_LINES 0x01f
-#define GICD_TYPE_CPUS  0x0e0
-#define GICD_TYPE_SEC   0x400
-
-#define GICC_CTL_ENABLE 0x1
-#define GICC_CTL_EOI    (0x1 << 9)
-
-#define GICC_IA_IRQ       0x03ff
-#define GICC_IA_CPU_MASK  0x1c00
-#define GICC_IA_CPU_SHIFT 10
-
-#define GICH_HCR_EN       (1 << 0)
-#define GICH_HCR_UIE      (1 << 1)
-#define GICH_HCR_LRENPIE  (1 << 2)
-#define GICH_HCR_NPIE     (1 << 3)
-#define GICH_HCR_VGRP0EIE (1 << 4)
-#define GICH_HCR_VGRP0DIE (1 << 5)
-#define GICH_HCR_VGRP1EIE (1 << 6)
-#define GICH_HCR_VGRP1DIE (1 << 7)
-
-#define GICH_MISR_EOI     (1 << 0)
-#define GICH_MISR_U       (1 << 1)
-#define GICH_MISR_LRENP   (1 << 2)
-#define GICH_MISR_NP      (1 << 3)
-#define GICH_MISR_VGRP0E  (1 << 4)
-#define GICH_MISR_VGRP0D  (1 << 5)
-#define GICH_MISR_VGRP1E  (1 << 6)
-#define GICH_MISR_VGRP1D  (1 << 7)
-
-#define GICH_LR_VIRTUAL_MASK    0x3ff
-#define GICH_LR_VIRTUAL_SHIFT   0
-#define GICH_LR_PHYSICAL_MASK   0x3ff
-#define GICH_LR_PHYSICAL_SHIFT  10
-#define GICH_LR_STATE_MASK      0x3
-#define GICH_LR_STATE_SHIFT     28
-#define GICH_LR_PRIORITY_SHIFT  23
-#define GICH_LR_MAINTENANCE_IRQ (1<<19)
-#define GICH_LR_PENDING         (1<<28)
-#define GICH_LR_ACTIVE          (1<<29)
-#define GICH_LR_GRP1            (1<<30)
-#define GICH_LR_HW              (1<<31)
-#define GICH_LR_CPUID_SHIFT     9
-#define GICH_VTR_NRLRGS         0x3f
-
-#define GICH_VMCR_PRIORITY_MASK   0x1f
-#define GICH_VMCR_PRIORITY_SHIFT  27
-
 /*
  * The minimum GICC_BPR is required to be in the range 0-3. We set
  * GICC_BPR to 0 but we must expect that it might be 3. This means we
@@ -157,6 +39,9 @@
 #define GIC_PRI_IPI        0x90 /* IPIs must preempt normal interrupts */
 #define GIC_PRI_HIGHEST    0x80 /* Higher priorities belong to Secure-World */
 
+#define SGI_TARGET_LIST    0
+#define SGI_TARGET_OTHERS  1
+#define SGI_TARGET_SELF    2
 
 #ifndef __ASSEMBLY__
 #include <xen/device_tree.h>
diff --git a/xen/include/asm-arm/gic_v2_defs.h b/xen/include/asm-arm/gic_v2_defs.h
new file mode 100644
index 0000000..033d826
--- /dev/null
+++ b/xen/include/asm-arm/gic_v2_defs.h
@@ -0,0 +1,144 @@
+/*
+ * ARM Generic Interrupt Controller v2 support
+ *
+ * Tim Deegan <tim@xen.org>
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARM_GIC_V2_DEFS_H__
+#define __ASM_ARM_GIC_V2_DEFS_H__
+
+#define GICD_CTLR       (0x000/4)
+#define GICD_TYPER      (0x004/4)
+#define GICD_IIDR       (0x008/4)
+#define GICD_IGROUPR    (0x080/4)
+#define GICD_IGROUPRN   (0x0FC/4)
+#define GICD_ISENABLER  (0x100/4)
+#define GICD_ISENABLERN (0x17C/4)
+#define GICD_ICENABLER  (0x180/4)
+#define GICD_ICENABLERN (0x1fC/4)
+#define GICD_ISPENDR    (0x200/4)
+#define GICD_ISPENDRN   (0x27C/4)
+#define GICD_ICPENDR    (0x280/4)
+#define GICD_ICPENDRN   (0x2FC/4)
+#define GICD_ISACTIVER  (0x300/4)
+#define GICD_ISACTIVERN (0x37C/4)
+#define GICD_ICACTIVER  (0x380/4)
+#define GICD_ICACTIVERN (0x3FC/4)
+#define GICD_IPRIORITYR (0x400/4)
+#define GICD_IPRIORITYRN (0x7F8/4)
+#define GICD_ITARGETSR  (0x800/4)
+#define GICD_ITARGETSRN (0xBF8/4)
+#define GICD_ICFGR      (0xC00/4)
+#define GICD_ICFGRN     (0xCFC/4)
+#define GICD_NSACR      (0xE00/4)
+#define GICD_NSACRN     (0xEFC/4)
+#define GICD_SGIR       (0xF00/4)
+#define GICD_CPENDSGIR  (0xF10/4)
+#define GICD_CPENDSGIRN (0xF1C/4)
+#define GICD_SPENDSGIR  (0xF20/4)
+#define GICD_SPENDSGIRN (0xF2C/4)
+#define GICD_ICPIDR2    (0xFE8/4)
+
+#define GICD_SGI_TARGET_LIST_SHIFT   (24)
+#define GICD_SGI_TARGET_LIST_MASK    (0x3UL << GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_LIST         (0UL<<GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_OTHERS       (1UL<<GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_SELF         (2UL<<GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_SHIFT        (16)
+#define GICD_SGI_TARGET_MASK         (0xFFUL<<GICD_SGI_TARGET_SHIFT)
+#define GICD_SGI_GROUP1              (1UL<<15)
+#define GICD_SGI_INTID_MASK          (0xFUL)
+
+#define GICC_CTLR       (0x0000/4)
+#define GICC_PMR        (0x0004/4)
+#define GICC_BPR        (0x0008/4)
+#define GICC_IAR        (0x000C/4)
+#define GICC_EOIR       (0x0010/4)
+#define GICC_RPR        (0x0014/4)
+#define GICC_HPPIR      (0x0018/4)
+#define GICC_APR        (0x00D0/4)
+#define GICC_NSAPR      (0x00E0/4)
+#define GICC_DIR        (0x1000/4)
+
+#define GICH_HCR        (0x00/4)
+#define GICH_VTR        (0x04/4)
+#define GICH_VMCR       (0x08/4)
+#define GICH_MISR       (0x10/4)
+#define GICH_EISR0      (0x20/4)
+#define GICH_EISR1      (0x24/4)
+#define GICH_ELSR0      (0x30/4)
+#define GICH_ELSR1      (0x34/4)
+#define GICH_APR        (0xF0/4)
+#define GICH_LR         (0x100/4)
+
+/* Register bits */
+#define GICD_CTL_ENABLE 0x1
+
+#define GICD_TYPE_LINES 0x01f
+#define GICD_TYPE_CPUS  0x0e0
+#define GICD_TYPE_SEC   0x400
+
+#define GICC_CTL_ENABLE 0x1
+#define GICC_CTL_EOI    (0x1 << 9)
+
+#define GICC_IA_IRQ       0x03ff
+#define GICC_IA_CPU_MASK  0x1c00
+#define GICC_IA_CPU_SHIFT 10
+
+#define GICH_HCR_EN       (1 << 0)
+#define GICH_HCR_UIE      (1 << 1)
+#define GICH_HCR_LRENPIE  (1 << 2)
+#define GICH_HCR_NPIE     (1 << 3)
+#define GICH_HCR_VGRP0EIE (1 << 4)
+#define GICH_HCR_VGRP0DIE (1 << 5)
+#define GICH_HCR_VGRP1EIE (1 << 6)
+#define GICH_HCR_VGRP1DIE (1 << 7)
+
+#define GICH_MISR_EOI     (1 << 0)
+#define GICH_MISR_U       (1 << 1)
+#define GICH_MISR_LRENP   (1 << 2)
+#define GICH_MISR_NP      (1 << 3)
+#define GICH_MISR_VGRP0E  (1 << 4)
+#define GICH_MISR_VGRP0D  (1 << 5)
+#define GICH_MISR_VGRP1E  (1 << 6)
+#define GICH_MISR_VGRP1D  (1 << 7)
+
+#define GICH_LR_VIRTUAL_MASK    0x3ff
+#define GICH_LR_VIRTUAL_SHIFT   0
+#define GICH_LR_PHYSICAL_MASK   0x3ff
+#define GICH_LR_PHYSICAL_SHIFT  10
+#define GICH_LR_STATE_MASK      0x3
+#define GICH_LR_STATE_SHIFT     28
+#define GICH_LR_PRIORITY_SHIFT  23
+#define GICH_LR_MAINTENANCE_IRQ (1<<19)
+#define GICH_LR_PENDING         (1<<28)
+#define GICH_LR_ACTIVE          (1<<29)
+#define GICH_LR_GRP1            (1<<30)
+#define GICH_LR_HW              (1<<31)
+#define GICH_LR_CPUID_SHIFT     9
+#define GICH_VTR_NRLRGS         0x3f
+
+#define GICH_VMCR_PRIORITY_MASK   0x1f
+#define GICH_VMCR_PRIORITY_SHIFT  27
+
+#endif /* __ASM_ARM_GIC_V2_DEFS_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (4 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 05/16] xen/arm: move gic definitions to seperate file vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-23 14:35   ` Ian Campbell
  2014-05-12 13:49   ` Julien Grall
  2014-04-15 11:17 ` [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality vijay.kilari
                   ` (9 subsequent siblings)
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

spinlock is used across generic and GIC low level
functions. Move this lock out of gic data.
This helps to separate generic and low level functions
later.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic.c |   35 ++++++++++++++++++-----------------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 05f2240..7c9a408 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -35,6 +35,8 @@
 #include <asm/gic_v2_defs.h>
 #include <asm/gic.h>
 
+static spinlock_t gic_lock;
+
 /* Access to the GIC Distributor registers through the fixmap */
 #define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
 #define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1))
@@ -50,7 +52,6 @@ static struct {
     unsigned int lines;  /* Number of interrupts (SPIs + PPIs + SGIs) */
     struct dt_irq maintenance; /* IRQ maintenance */
     unsigned int cpus;
-    spinlock_t lock;
 } gic;
 
 static irq_desc_t irq_desc[NR_IRQS];
@@ -142,12 +143,12 @@ static void gic_irq_enable(struct irq_desc *desc)
     unsigned long flags;
 
     spin_lock_irqsave(&desc->lock, flags);
-    spin_lock(&gic.lock);
+    spin_lock(&gic_lock);
     desc->status &= ~IRQ_DISABLED;
     dsb();
     /* Enable routing */
     GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
-    spin_unlock(&gic.lock);
+    spin_unlock(&gic_lock);
     spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -157,11 +158,11 @@ static void gic_irq_disable(struct irq_desc *desc)
     unsigned long flags;
 
     spin_lock_irqsave(&desc->lock, flags);
-    spin_lock(&gic.lock);
+    spin_lock(&gic_lock);
     /* Disable routing */
     GICD[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
     desc->status |= IRQ_DISABLED;
-    spin_unlock(&gic.lock);
+    spin_unlock(&gic_lock);
     spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -226,7 +227,7 @@ static hw_irq_controller gic_guest_irq_type = {
 };
 
 /*
- * - needs to be called with gic.lock held
+ * - needs to be called with gic_lock held
  * - needs to be called with a valid cpu_mask, ie each cpu in the mask has
  * already called gic_cpu_init
  */
@@ -277,9 +278,9 @@ static int gic_route_irq(unsigned int irq, bool_t level,
 
     desc->handler = &gic_host_irq_type;
 
-    spin_lock(&gic.lock);
+    spin_lock(&gic_lock);
     gic_set_irq_properties(irq, level, cpu_mask, priority);
-    spin_unlock(&gic.lock);
+    spin_unlock(&gic_lock);
 
     spin_unlock_irqrestore(&desc->lock, flags);
     return 0;
@@ -471,14 +472,14 @@ void __init gic_init(void)
     set_fixmap(FIXMAP_GICH, gic.hbase >> PAGE_SHIFT, DEV_SHARED);
 
     /* Global settings: interrupt distributor */
-    spin_lock_init(&gic.lock);
-    spin_lock(&gic.lock);
+    spin_lock_init(&gic_lock);
+    spin_lock(&gic_lock);
 
     gic_dist_init();
     gic_cpu_init();
     gic_hyp_init();
 
-    spin_unlock(&gic.lock);
+    spin_unlock(&gic_lock);
 }
 
 void send_sgi(const cpumask_t *online_mask, enum gic_sgi sgi, uint8_t irqmode)
@@ -550,10 +551,10 @@ void smp_send_state_dump(unsigned int cpu)
 /* Set up the per-CPU parts of the GIC for a secondary CPU */
 void __cpuinit gic_init_secondary_cpu(void)
 {
-    spin_lock(&gic.lock);
+    spin_lock(&gic_lock);
     gic_cpu_init();
     gic_hyp_init();
-    spin_unlock(&gic.lock);
+    spin_unlock(&gic_lock);
 }
 
 /* Shut down the per-CPU GIC interface */
@@ -561,10 +562,10 @@ void gic_disable_cpu(void)
 {
     ASSERT(!local_irq_is_enabled());
 
-    spin_lock(&gic.lock);
+    spin_lock(&gic_lock);
     gic_cpu_disable();
     gic_hyp_disable();
-    spin_unlock(&gic.lock);
+    spin_unlock(&gic_lock);
 }
 
 void gic_route_ppis(void)
@@ -911,7 +912,7 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
     action->free_on_release = 1;
 
     spin_lock_irqsave(&desc->lock, flags);
-    spin_lock(&gic.lock);
+    spin_lock(&gic_lock);
 
     desc->handler = &gic_guest_irq_type;
     desc->status |= IRQ_GUEST;
@@ -932,7 +933,7 @@ int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
     p->desc = desc;
 
 out:
-    spin_unlock(&gic.lock);
+    spin_unlock(&gic_lock);
     spin_unlock_irqrestore(&desc->lock, flags);
     return retval;
 }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (5 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 18:35   ` Julien Grall
                     ` (2 more replies)
  2014-04-15 11:17 ` [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver vijay.kilari
                   ` (8 subsequent siblings)
  15 siblings, 3 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

GIC driver contains both generic and hardware specific low
level functionality in gic.c file.

With this patch, low level functionality is moved to separate
file gic-v2.c and generic code is kept in gic.c file

Callbacks are registered by low level driver with generic driver
and are called whereever required.

The locking mechanism is now kept in generic code as is and
hence it is upto generic driver to take proper locks before
calling low level driver callbacks.

This helps to separate generic and hardware functionality
and implement future hardware version drivers.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/Makefile             |    2 +-
 xen/arch/arm/gic-v2.c             |  532 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic.c                |  423 +++++------------------------
 xen/include/asm-arm/gic.h         |   86 ++++++
 xen/include/asm-arm/gic_v2_defs.h |   16 +-
 5 files changed, 689 insertions(+), 370 deletions(-)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 63e0460..969ee52 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -10,7 +10,7 @@ obj-y += vpsci.o
 obj-y += domctl.o
 obj-y += sysctl.o
 obj-y += domain_build.o
-obj-y += gic.o
+obj-y += gic.o gic-v2.o
 obj-y += io.o
 obj-y += irq.o
 obj-y += kernel.o
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
new file mode 100644
index 0000000..0c0fa86
--- /dev/null
+++ b/xen/arch/arm/gic-v2.c
@@ -0,0 +1,532 @@
+/*
+ * xen/arch/arm/gic-v2.c
+ *
+ * ARM Generic Interrupt Controller support v2
+ *
+ * Tim Deegan <tim@xen.org>
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/errno.h>
+#include <xen/serial.h>
+#include <xen/softirq.h>
+#include <xen/list.h>
+#include <xen/device_tree.h>
+#include <asm/p2m.h>
+#include <asm/domain.h>
+#include <asm/platform.h>
+
+#include <asm/gic_v2_defs.h>
+#include <asm/gic.h>
+
+/* Access to the GIC Distributor registers through the fixmap */
+#define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
+#define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1))
+#define GICH ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICH))
+
+/* Global state */
+static struct {
+    paddr_t dbase;       /* Address of distributor registers */
+    paddr_t cbase;       /* Address of CPU interface registers */
+    paddr_t hbase;       /* Address of virtual interface registers */
+    paddr_t vbase;       /* Address of virtual cpu interface registers */
+    unsigned int lines;  /* Number of interrupts (SPIs + PPIs + SGIs) */
+    struct dt_irq maintenance; /* IRQ maintenance */
+    unsigned int cpus;
+} gic;
+
+static struct gic_hw_operations gic_ops;
+
+static uint8_t nr_lrs;
+
+/* The GIC mapping of CPU interfaces does not necessarily match the
+ * logical CPU numbering. Let's use mapping as returned by the GIC
+ * itself
+ */
+static DEFINE_PER_CPU(u8, gic_cpu_id);
+
+/* Maximum cpu interface per GIC */
+#define NR_GIC_CPU_IF 8
+
+static unsigned int gicv2_cpu_mask(const cpumask_t *cpumask)
+{
+    unsigned int cpu;
+    unsigned int mask = 0;
+    cpumask_t possible_mask;
+
+    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
+    for_each_cpu(cpu, &possible_mask)
+    {
+        ASSERT(cpu < NR_GIC_CPU_IF);
+        mask |= per_cpu(gic_cpu_id, cpu);
+    }
+
+    return mask;
+}
+
+static void gicv2_save_state(struct vcpu *v)
+{
+    int i;
+
+    /* No need for spinlocks here because interrupts are disabled around
+     * this call and it only accesses struct vcpu fields that cannot be
+     * accessed simultaneously by another pCPU.
+     */
+    for ( i = 0; i < nr_lrs; i++ )
+        v->arch.gic_lr[i] = GICH[GICH_LR + i];
+    v->arch.gic_apr = GICH[GICH_APR];
+    v->arch.gic_vmcr = GICH[GICH_VMCR];
+    /* Disable until next VCPU scheduled */
+    GICH[GICH_HCR] = 0;
+}
+
+static void gicv2_restore_state(struct vcpu *v)
+{
+    int i;
+
+    for ( i = 0; i < nr_lrs; i++ )
+        GICH[GICH_LR + i] = v->arch.gic_lr[i];
+    GICH[GICH_APR] = v->arch.gic_apr;
+    GICH[GICH_VMCR] = v->arch.gic_vmcr;
+    GICH[GICH_HCR] = GICH_HCR_EN;
+}
+
+static void gicv2_dump_state(struct vcpu *v)
+{
+    int i;
+    if ( v == current )
+    {
+        for ( i = 0; i < nr_lrs; i++ )
+            printk("   HW_LR[%d]=%x\n", i, GICH[GICH_LR + i]);
+    } else {
+        for ( i = 0; i < nr_lrs; i++ )
+            printk("   VCPU_LR[%d]=%x\n", i, v->arch.gic_lr[i]);
+    }
+}
+
+static void gicv2_enable_irq(struct irq_desc *irqd)
+{
+    int irq = irqd->irq;
+    /* Enable routing */
+    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
+}
+
+static void gicv2_disable_irq(struct irq_desc *irqd)
+{
+    int irq = irqd->irq;
+    /* Disable routing */
+    GICD[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
+}
+
+static void gicv2_eoi_irq(struct irq_desc *irqd)
+{
+    int irq = irqd->irq;
+    /* Lower the priority */
+    GICC[GICC_EOIR] = irq;
+}
+
+static void gicv2_dir_irq(int irq)
+{
+    /* Deactivate */
+    GICC[GICC_DIR] = irq;
+}
+
+static unsigned int gicv2_ack_irq(void)
+{
+    return (GICC[GICC_IAR] & GICC_IA_IRQ);
+}
+
+/*
+ * - needs to be called with gic_lock held
+ * - needs to be called with a valid cpu_mask, ie each cpu in the mask has
+ * already called gic_cpu_init
+ */
+static void gicv2_set_irq_properties(unsigned int irq, bool_t level,
+                                   const cpumask_t *cpu_mask,
+                                   unsigned int priority)
+{
+    volatile unsigned char *bytereg;
+    uint32_t cfg, edgebit;
+    unsigned int mask = gicv2_cpu_mask(cpu_mask);
+
+    /* Set edge / level */
+    cfg = GICD[GICD_ICFGR + irq / 16];
+    edgebit = 2u << (2 * (irq % 16));
+    if ( level )
+        cfg &= ~edgebit;
+    else
+        cfg |= edgebit;
+    GICD[GICD_ICFGR + irq / 16] = cfg;
+
+    /* Set target CPU mask (RAZ/WI on uniprocessor) */
+    bytereg = (unsigned char *) (GICD + GICD_ITARGETSR);
+    bytereg[irq] = mask;
+
+    /* Set priority */
+    bytereg = (unsigned char *) (GICD + GICD_IPRIORITYR);
+    bytereg[irq] = priority;
+
+}
+
+static void __init gicv2_dist_init(void)
+{
+    uint32_t type;
+    uint32_t cpumask;
+    int i;
+
+    cpumask = GICD[GICD_ITARGETSR] & 0xff;
+    cpumask |= cpumask << 8;
+    cpumask |= cpumask << 16;
+
+    /* Disable the distributor */
+    GICD[GICD_CTLR] = 0;
+
+    type = GICD[GICD_TYPER];
+    gic.lines = 32 * ((type & GICD_TYPE_LINES) + 1);
+    gic.cpus = 1 + ((type & GICD_TYPE_CPUS) >> 5);
+    printk("GIC: %d lines, %d cpu%s%s (IID %8.8x).\n",
+           gic.lines, gic.cpus, (gic.cpus == 1) ? "" : "s",
+           (type & GICD_TYPE_SEC) ? ", secure" : "",
+           GICD[GICD_IIDR]);
+
+    gic_ops.nr_lines = gic.lines;
+    /* Default all global IRQs to level, active low */
+    for ( i = 32; i < gic.lines; i += 16 )
+        GICD[GICD_ICFGR + i / 16] = 0x0;
+
+    /* Route all global IRQs to this CPU */
+    for ( i = 32; i < gic.lines; i += 4 )
+        GICD[GICD_ITARGETSR + i / 4] = cpumask;
+
+    /* Default priority for global interrupts */
+    for ( i = 32; i < gic.lines; i += 4 )
+        GICD[GICD_IPRIORITYR + i / 4] =
+            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | GIC_PRI_IRQ;
+
+    /* Disable all global interrupts */
+    for ( i = 32; i < gic.lines; i += 32 )
+        GICD[GICD_ICENABLER + i / 32] = (uint32_t)~0ul;
+
+    /* Turn on the distributor */
+    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
+}
+
+static void __cpuinit gicv2_cpu_init(void)
+{
+    int i;
+
+    this_cpu(gic_cpu_id) = GICD[GICD_ITARGETSR] & 0xff;
+
+    /* The first 32 interrupts (PPI and SGI) are banked per-cpu, so
+     * even though they are controlled with GICD registers, they must
+     * be set up here with the other per-cpu state. */
+    GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
+    GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */
+    /* Set SGI priorities */
+    for ( i = 0; i < 16; i += 4 )
+        GICD[GICD_IPRIORITYR + i / 4] =
+            GIC_PRI_IPI<<24 | GIC_PRI_IPI<<16 | GIC_PRI_IPI<<8 | GIC_PRI_IPI;
+    /* Set PPI priorities */
+    for ( i = 16; i < 32; i += 4 )
+        GICD[GICD_IPRIORITYR + i / 4] =
+            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | GIC_PRI_IRQ;
+
+    /* Local settings: interface controller */
+    GICC[GICC_PMR] = 0xff;                /* Don't mask by priority */
+    GICC[GICC_BPR] = 0;                   /* Finest granularity of priority */
+    GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI;    /* Turn on delivery */
+}
+
+static void gicv2_cpu_disable(void)
+{
+    GICC[GICC_CTLR] = 0;
+}
+
+static void __cpuinit gicv2_hyp_init(void)
+{
+    uint32_t vtr;
+
+    vtr = GICH[GICH_VTR];
+    nr_lrs  = (vtr & GICH_VTR_NRLRGS) + 1;
+    gic_ops.nr_lrs = nr_lrs;
+
+    GICH[GICH_MISR] = GICH_MISR_EOI;
+    update_cpu_lr_mask();
+}
+
+static void __cpuinit gicv2_hyp_disable(void)
+{
+    GICH[GICH_HCR] = 0;
+}
+
+/* Set up the GIC */
+void __init gicv2_init(void)
+{
+    static const struct dt_device_match gic_ids[] __initconst =
+    {
+        DT_MATCH_GIC,
+        { /* sentinel */ },
+    };
+    struct dt_device_node *node;
+    int res;
+
+    node = dt_find_interrupt_controller(gic_ids);
+    if ( !node )
+        panic("Unable to find compatible GIC in the device tree");
+
+    dt_device_set_used_by(node, DOMID_XEN);
+
+    res = dt_device_get_address(node, 0, &gic.dbase, NULL);
+    if ( res || !gic.dbase || (gic.dbase & ~PAGE_MASK) )
+        panic("GIC: Cannot find a valid address for the distributor");
+
+    res = dt_device_get_address(node, 1, &gic.cbase, NULL);
+    if ( res || !gic.cbase || (gic.cbase & ~PAGE_MASK) )
+        panic("GIC: Cannot find a valid address for the CPU");
+
+    res = dt_device_get_address(node, 2, &gic.hbase, NULL);
+    if ( res || !gic.hbase || (gic.hbase & ~PAGE_MASK) )
+        panic("GIC: Cannot find a valid address for the hypervisor");
+
+    res = dt_device_get_address(node, 3, &gic.vbase, NULL);
+    if ( res || !gic.vbase || (gic.vbase & ~PAGE_MASK) )
+        panic("GIC: Cannot find a valid address for the virtual CPU");
+
+    res = dt_device_get_irq(node, 0, &gic.maintenance);
+    if ( res )
+        panic("GIC: Cannot find the maintenance IRQ");
+
+    /* Set the GIC as the primary interrupt controller */
+    dt_interrupt_controller = node;
+
+    /* TODO: Add check on distributor, cpu size */
+
+    printk("GIC initialization:\n"
+              "        gic_dist_addr=%"PRIpaddr"\n"
+              "        gic_cpu_addr=%"PRIpaddr"\n"
+              "        gic_hyp_addr=%"PRIpaddr"\n"
+              "        gic_vcpu_addr=%"PRIpaddr"\n"
+              "        gic_maintenance_irq=%u\n",
+              gic.dbase, gic.cbase, gic.hbase, gic.vbase,
+              gic.maintenance.irq);
+
+    if ( (gic.dbase & ~PAGE_MASK) || (gic.cbase & ~PAGE_MASK) ||
+         (gic.hbase & ~PAGE_MASK) || (gic.vbase & ~PAGE_MASK) )
+        panic("GIC interfaces not page aligned");
+
+    set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED);
+    BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) !=
+                 FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE);
+    set_fixmap(FIXMAP_GICC1, gic.cbase >> PAGE_SHIFT, DEV_SHARED);
+    if ( platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
+        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x10, DEV_SHARED);
+    else
+        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x1, DEV_SHARED);
+    set_fixmap(FIXMAP_GICH, gic.hbase >> PAGE_SHIFT, DEV_SHARED);
+
+    /* Global settings: interrupt distributor */
+
+    gicv2_dist_init();
+    gicv2_cpu_init();
+    gicv2_hyp_init();
+
+    gic_ops.hw_version = GIC_V2;
+    register_gic_ops(&gic_ops);
+}
+
+static void gicv2_secondary_cpu_init(void)
+{
+    gicv2_cpu_init();
+    gicv2_hyp_init();
+}
+
+static struct dt_irq * gicv2_maintenance_irq(void)
+{
+    return &gic.maintenance;
+}
+
+static void gicv2_send_sgi(const cpumask_t *online_mask, enum gic_sgi sgi, uint8_t irqmode)
+{
+    unsigned int mask = 0;
+
+    switch(irqmode)
+    {
+    case SGI_TARGET_OTHERS:
+        GICD[GICD_SGIR] = GICD_SGI_TARGET_OTHERS | sgi;
+        break;
+    case SGI_TARGET_SELF:
+        GICD[GICD_SGIR] = GICD_SGI_TARGET_SELF | sgi;
+        break;
+    case SGI_TARGET_LIST:
+        mask = gicv2_cpu_mask(online_mask);
+        GICD[GICD_SGIR] = GICD_SGI_TARGET_LIST |
+                          (mask<<GICD_SGI_TARGET_SHIFT) | sgi;
+        break;
+    default:
+         gdprintk(XENLOG_WARNING, "Wrong sgi irq mode for sgi %x\n", sgi);
+    }
+}
+
+/* Shut down the per-CPU GIC interface */
+static void gicv2_disable_interface(void)
+{
+    gicv2_cpu_disable();
+    gicv2_hyp_disable();
+}
+
+static void gicv2_update_lr(int lr, struct pending_irq *p, unsigned int state)
+{
+    int maintenance_int = GICH_LR_MAINTENANCE_IRQ;
+
+    BUG_ON(lr >= nr_lrs);
+    BUG_ON(lr < 0);
+    BUG_ON(state & ~(GICH_LR_STATE_MASK<<GICH_LR_STATE_SHIFT));
+
+    GICH[GICH_LR + lr] = ((state & 0x3) << GICH_LR_STATE_SHIFT) |
+        maintenance_int |
+        ((p->priority >> 3) << GICH_LR_PRIORITY_SHIFT) |
+        ((p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
+}
+
+static void gicv2_clear_lr(int lr)
+{
+    GICH[GICH_LR + lr] = 0;
+}
+
+static int gicv_v2_init(struct domain *d)
+{
+    int ret;
+
+    /*
+     * Domain 0 gets the hardware address.
+     * Guests get the virtual platform layout.
+     */
+    if ( d->domain_id == 0 )
+    {
+        d->arch.vgic.dbase = gic.dbase;
+        d->arch.vgic.cbase = gic.cbase;
+    }
+    else
+    {
+        d->arch.vgic.dbase = GUEST_GICD_BASE;
+        d->arch.vgic.cbase = GUEST_GICC_BASE;
+    }
+
+    d->arch.vgic.nr_lines = 0;
+
+    /*
+     * Map the gic virtual cpu interface in the gic cpu interface
+     * region of the guest.
+     *
+     * The second page is always mapped at +4K irrespective of the
+     * GIC_64K_STRIDE quirk. The DTB passed to the guest reflects this.
+     */
+    ret = map_mmio_regions(d, d->arch.vgic.cbase,
+                           d->arch.vgic.cbase + PAGE_SIZE - 1,
+                           gic.vbase);
+    if ( ret )
+        return ret;
+
+    if ( !platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
+        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
+                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
+                               gic.vbase + PAGE_SIZE);
+    else
+        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
+                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
+                               gic.vbase + 16*PAGE_SIZE);
+
+    return ret;
+
+}
+
+static void gicv2_read_lr(int lr, struct gic_lr *lr_reg)
+{
+    uint32_t lrv;
+
+    lrv = GICH[GICH_LR + lr];
+    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
+    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK;
+    lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK;
+    lr_reg->state    = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
+    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;
+    lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;
+}
+
+static void gicv2_write_lr(int lr, struct gic_lr *lr_reg)
+{
+    uint32_t lrv = 0;
+    lrv = ( ((lr_reg->pirq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT)  |
+            ((lr_reg->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT)   |
+            ((uint32_t)(lr_reg->priority & GICH_LR_PRIORITY_MASK) << GICH_LR_PRIORITY_SHIFT) |
+            ((uint32_t)(lr_reg->state & GICH_LR_STATE_MASK) << GICH_LR_STATE_SHIFT) |
+            ((uint32_t)(lr_reg->hw_status & GICH_LR_HW_MASK)  << GICH_LR_HW_SHIFT)  |
+            ((uint32_t)(lr_reg->grp & GICH_LR_GRP_MASK) << GICH_LR_GRP_SHIFT) );
+
+    GICH[GICH_LR + lr] = lrv;
+}
+
+static void gicv2_hcr_status(uint32_t flag, bool_t status)
+{
+    if ( status )
+      GICH[GICH_HCR] |= flag;
+    else
+      GICH[GICH_HCR] &= ~flag;
+}
+
+static unsigned int gicv2_read_vmcr_priority(void)
+{
+   return (GICH[GICH_VMCR] >> GICH_VMCR_PRIORITY_SHIFT) & GICH_VMCR_PRIORITY_MASK;
+}
+
+static hw_irq_controller irq_ops = {
+    .enable              = gicv2_enable_irq,
+    .disable             = gicv2_disable_irq,
+    .end                 = gicv2_eoi_irq,
+};
+
+static struct gic_hw_operations gic_ops = {
+    .secondary_init      = gicv2_secondary_cpu_init,
+    .get_maintenance_irq = gicv2_maintenance_irq,
+    .save_state          = gicv2_save_state,
+    .restore_state       = gicv2_restore_state,
+    .dump_state          = gicv2_dump_state,
+    .gicv_setup          = gicv_v2_init,
+    .gic_irq_ops         = &irq_ops,
+    .deactivate_irq      = gicv2_dir_irq,
+    .ack_irq             = gicv2_ack_irq,
+    .set_irq_property    = gicv2_set_irq_properties,
+    .send_sgi            = gicv2_send_sgi,
+    .disable_interface   = gicv2_disable_interface,
+    .update_lr           = gicv2_update_lr,
+    .update_hcr_status   = gicv2_hcr_status,
+    .clear_lr            = gicv2_clear_lr,
+    .read_lr             = gicv2_read_lr,
+    .write_lr            = gicv2_write_lr,
+    .read_vmcr_priority  = gicv2_read_vmcr_priority,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 7c9a408..ce21ef6 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -32,65 +32,39 @@
 #include <asm/domain.h>
 #include <asm/platform.h>
 
-#include <asm/gic_v2_defs.h>
 #include <asm/gic.h>
 
 static spinlock_t gic_lock;
-
-/* Access to the GIC Distributor registers through the fixmap */
-#define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
-#define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1))
-#define GICH ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICH))
 static void gic_restore_pending_irqs(struct vcpu *v);
 
-/* Global state */
-static struct {
-    paddr_t dbase;       /* Address of distributor registers */
-    paddr_t cbase;       /* Address of CPU interface registers */
-    paddr_t hbase;       /* Address of virtual interface registers */
-    paddr_t vbase;       /* Address of virtual cpu interface registers */
-    unsigned int lines;  /* Number of interrupts (SPIs + PPIs + SGIs) */
-    struct dt_irq maintenance; /* IRQ maintenance */
-    unsigned int cpus;
-} gic;
-
 static irq_desc_t irq_desc[NR_IRQS];
 static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
 static DEFINE_PER_CPU(uint64_t, lr_mask);
 
-static uint8_t nr_lrs;
-#define lr_all_full() (this_cpu(lr_mask) == ((1 << nr_lrs) - 1))
-
-/* The GIC mapping of CPU interfaces does not necessarily match the
- * logical CPU numbering. Let's use mapping as returned by the GIC
- * itself
- */
-static DEFINE_PER_CPU(u8, gic_cpu_id);
-
-/* Maximum cpu interface per GIC */
-#define NR_GIC_CPU_IF 8
+#define lr_all_full() (this_cpu(lr_mask) == ((1 << gic_hw_ops->nr_lrs) - 1))
 
 static void gic_clear_one_lr(struct vcpu *v, int i);
 
-static unsigned int gic_cpu_mask(const cpumask_t *cpumask)
+static const struct gic_hw_operations *gic_hw_ops;
+
+void register_gic_ops(const struct gic_hw_operations *ops)
 {
-    unsigned int cpu;
-    unsigned int mask = 0;
-    cpumask_t possible_mask;
+    gic_hw_ops = ops;
+}
 
-    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
-    for_each_cpu(cpu, &possible_mask)
-    {
-        ASSERT(cpu < NR_GIC_CPU_IF);
-        mask |= per_cpu(gic_cpu_id, cpu);
-    }
+void update_cpu_lr_mask(void)
+{
+    this_cpu(lr_mask) = 0ULL;
+}
 
-    return mask;
+int gic_hw_version(void)
+{
+   return gic_hw_ops->hw_version;
 }
 
 unsigned int gic_number_lines(void)
 {
-    return gic.lines;
+    return gic_hw_ops->nr_lines;
 }
 
 irq_desc_t *__irq_to_desc(int irq)
@@ -101,37 +75,29 @@ irq_desc_t *__irq_to_desc(int irq)
 
 void gic_save_state(struct vcpu *v)
 {
-    int i;
     ASSERT(!local_irq_is_enabled());
 
+    if ( is_idle_vcpu(v) )
+        return;
     /* No need for spinlocks here because interrupts are disabled around
      * this call and it only accesses struct vcpu fields that cannot be
      * accessed simultaneously by another pCPU.
      */
-    for ( i=0; i<nr_lrs; i++)
-        v->arch.gic_lr[i] = GICH[GICH_LR + i];
     v->arch.lr_mask = this_cpu(lr_mask);
-    v->arch.gic_apr = GICH[GICH_APR];
-    v->arch.gic_vmcr = GICH[GICH_VMCR];
-    /* Disable until next VCPU scheduled */
-    GICH[GICH_HCR] = 0;
+    gic_hw_ops->save_state(v);
     isb();
 }
 
 void gic_restore_state(struct vcpu *v)
 {
-    int i;
     ASSERT(!local_irq_is_enabled());
 
     if ( is_idle_vcpu(v) )
         return;
 
     this_cpu(lr_mask) = v->arch.lr_mask;
-    for ( i=0; i<nr_lrs; i++)
-        GICH[GICH_LR + i] = v->arch.gic_lr[i];
-    GICH[GICH_APR] = v->arch.gic_apr;
-    GICH[GICH_VMCR] = v->arch.gic_vmcr;
-    GICH[GICH_HCR] = GICH_HCR_EN;
+    gic_hw_ops->restore_state(v);
+
     isb();
 
     gic_restore_pending_irqs(v);
@@ -139,7 +105,6 @@ void gic_restore_state(struct vcpu *v)
 
 static void gic_irq_enable(struct irq_desc *desc)
 {
-    int irq = desc->irq;
     unsigned long flags;
 
     spin_lock_irqsave(&desc->lock, flags);
@@ -147,20 +112,19 @@ static void gic_irq_enable(struct irq_desc *desc)
     desc->status &= ~IRQ_DISABLED;
     dsb();
     /* Enable routing */
-    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
+    gic_hw_ops->gic_irq_ops->enable(desc);
     spin_unlock(&gic_lock);
     spin_unlock_irqrestore(&desc->lock, flags);
 }
 
 static void gic_irq_disable(struct irq_desc *desc)
 {
-    int irq = desc->irq;
     unsigned long flags;
 
     spin_lock_irqsave(&desc->lock, flags);
     spin_lock(&gic_lock);
     /* Disable routing */
-    GICD[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
+    gic_hw_ops->gic_irq_ops->disable(desc);
     desc->status |= IRQ_DISABLED;
     spin_unlock(&gic_lock);
     spin_unlock_irqrestore(&desc->lock, flags);
@@ -186,16 +150,15 @@ static void gic_host_irq_end(struct irq_desc *desc)
 {
     int irq = desc->irq;
     /* Lower the priority */
-    GICC[GICC_EOIR] = irq;
+    gic_hw_ops->gic_irq_ops->end(desc);
     /* Deactivate */
-    GICC[GICC_DIR] = irq;
+    gic_hw_ops->deactivate_irq(irq);
 }
 
 static void gic_guest_irq_end(struct irq_desc *desc)
 {
-    int irq = desc->irq;
     /* Lower the priority of the IRQ */
-    GICC[GICC_EOIR] = irq;
+    gic_hw_ops->gic_irq_ops->end(desc);
     /* Deactivation happens in maintenance interrupt / via GICV */
 }
 
@@ -215,6 +178,7 @@ static hw_irq_controller gic_host_irq_type = {
     .end = gic_host_irq_end,
     .set_affinity = gic_irq_set_affinity,
 };
+
 static hw_irq_controller gic_guest_irq_type = {
     .typename = "gic",
     .startup = gic_irq_startup,
@@ -235,27 +199,7 @@ static void gic_set_irq_properties(unsigned int irq, bool_t level,
                                    const cpumask_t *cpu_mask,
                                    unsigned int priority)
 {
-    volatile unsigned char *bytereg;
-    uint32_t cfg, edgebit;
-    unsigned int mask = gic_cpu_mask(cpu_mask);
-
-    /* Set edge / level */
-    cfg = GICD[GICD_ICFGR + irq / 16];
-    edgebit = 2u << (2 * (irq % 16));
-    if ( level )
-        cfg &= ~edgebit;
-    else
-        cfg |= edgebit;
-    GICD[GICD_ICFGR + irq / 16] = cfg;
-
-    /* Set target CPU mask (RAZ/WI on uniprocessor) */
-    bytereg = (unsigned char *) (GICD + GICD_ITARGETSR);
-    bytereg[irq] = mask;
-
-    /* Set priority */
-    bytereg = (unsigned char *) (GICD + GICD_IPRIORITYR);
-    bytereg[irq] = priority;
-
+   return gic_hw_ops->set_irq_property(irq, level, cpu_mask, priority);
 }
 
 /* Program the GIC to route an interrupt */
@@ -266,7 +210,7 @@ static int gic_route_irq(unsigned int irq, bool_t level,
     unsigned long flags;
 
     ASSERT(priority <= 0xff);     /* Only 8 bits of priority */
-    ASSERT(irq < gic.lines);      /* Can't route interrupts that don't exist */
+    ASSERT(irq < gic_number_lines());      /* Can't route interrupts that don't exist */
 
     if ( desc->action != NULL )
         return -EBUSY;
@@ -297,95 +241,6 @@ void gic_route_dt_irq(const struct dt_irq *irq, const cpumask_t *cpu_mask,
     gic_route_irq(irq->irq, level, cpu_mask, priority);
 }
 
-static void __init gic_dist_init(void)
-{
-    uint32_t type;
-    uint32_t cpumask;
-    int i;
-
-    cpumask = GICD[GICD_ITARGETSR] & 0xff;
-    cpumask |= cpumask << 8;
-    cpumask |= cpumask << 16;
-
-    /* Disable the distributor */
-    GICD[GICD_CTLR] = 0;
-
-    type = GICD[GICD_TYPER];
-    gic.lines = 32 * ((type & GICD_TYPE_LINES) + 1);
-    gic.cpus = 1 + ((type & GICD_TYPE_CPUS) >> 5);
-    printk("GIC: %d lines, %d cpu%s%s (IID %8.8x).\n",
-           gic.lines, gic.cpus, (gic.cpus == 1) ? "" : "s",
-           (type & GICD_TYPE_SEC) ? ", secure" : "",
-           GICD[GICD_IIDR]);
-
-    /* Default all global IRQs to level, active low */
-    for ( i = 32; i < gic.lines; i += 16 )
-        GICD[GICD_ICFGR + i / 16] = 0x0;
-
-    /* Route all global IRQs to this CPU */
-    for ( i = 32; i < gic.lines; i += 4 )
-        GICD[GICD_ITARGETSR + i / 4] = cpumask;
-
-    /* Default priority for global interrupts */
-    for ( i = 32; i < gic.lines; i += 4 )
-        GICD[GICD_IPRIORITYR + i / 4] =
-            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | GIC_PRI_IRQ;
-
-    /* Disable all global interrupts */
-    for ( i = 32; i < gic.lines; i += 32 )
-        GICD[GICD_ICENABLER + i / 32] = (uint32_t)~0ul;
-
-    /* Turn on the distributor */
-    GICD[GICD_CTLR] = GICD_CTL_ENABLE;
-}
-
-static void __cpuinit gic_cpu_init(void)
-{
-    int i;
-
-    this_cpu(gic_cpu_id) = GICD[GICD_ITARGETSR] & 0xff;
-
-    /* The first 32 interrupts (PPI and SGI) are banked per-cpu, so
-     * even though they are controlled with GICD registers, they must
-     * be set up here with the other per-cpu state. */
-    GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
-    GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */
-    /* Set SGI priorities */
-    for (i = 0; i < 16; i += 4)
-        GICD[GICD_IPRIORITYR + i / 4] =
-            GIC_PRI_IPI<<24 | GIC_PRI_IPI<<16 | GIC_PRI_IPI<<8 | GIC_PRI_IPI;
-    /* Set PPI priorities */
-    for (i = 16; i < 32; i += 4)
-        GICD[GICD_IPRIORITYR + i / 4] =
-            GIC_PRI_IRQ<<24 | GIC_PRI_IRQ<<16 | GIC_PRI_IRQ<<8 | GIC_PRI_IRQ;
-
-    /* Local settings: interface controller */
-    GICC[GICC_PMR] = 0xff;                /* Don't mask by priority */
-    GICC[GICC_BPR] = 0;                   /* Finest granularity of priority */
-    GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI;    /* Turn on delivery */
-}
-
-static void gic_cpu_disable(void)
-{
-    GICC[GICC_CTLR] = 0;
-}
-
-static void __cpuinit gic_hyp_init(void)
-{
-    uint32_t vtr;
-
-    vtr = GICH[GICH_VTR];
-    nr_lrs  = (vtr & GICH_VTR_NRLRGS) + 1;
-
-    GICH[GICH_MISR] = GICH_MISR_EOI;
-    this_cpu(lr_mask) = 0ULL;
-}
-
-static void __cpuinit gic_hyp_disable(void)
-{
-    GICH[GICH_HCR] = 0;
-}
-
 int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
                   unsigned int *out_hwirq,
                   unsigned int *out_type)
@@ -409,99 +264,8 @@ int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
 /* Set up the GIC */
 void __init gic_init(void)
 {
-    static const struct dt_device_match gic_ids[] __initconst =
-    {
-        DT_MATCH_GIC,
-        { /* sentinel */ },
-    };
-    struct dt_device_node *node;
-    int res;
-
-    node = dt_find_interrupt_controller(gic_ids);
-    if ( !node )
-        panic("Unable to find compatible GIC in the device tree");
-
-    dt_device_set_used_by(node, DOMID_XEN);
-
-    res = dt_device_get_address(node, 0, &gic.dbase, NULL);
-    if ( res || !gic.dbase || (gic.dbase & ~PAGE_MASK) )
-        panic("GIC: Cannot find a valid address for the distributor");
-
-    res = dt_device_get_address(node, 1, &gic.cbase, NULL);
-    if ( res || !gic.cbase || (gic.cbase & ~PAGE_MASK) )
-        panic("GIC: Cannot find a valid address for the CPU");
-
-    res = dt_device_get_address(node, 2, &gic.hbase, NULL);
-    if ( res || !gic.hbase || (gic.hbase & ~PAGE_MASK) )
-        panic("GIC: Cannot find a valid address for the hypervisor");
-
-    res = dt_device_get_address(node, 3, &gic.vbase, NULL);
-    if ( res || !gic.vbase || (gic.vbase & ~PAGE_MASK) )
-        panic("GIC: Cannot find a valid address for the virtual CPU");
-
-    res = dt_device_get_irq(node, 0, &gic.maintenance);
-    if ( res )
-        panic("GIC: Cannot find the maintenance IRQ");
-
-    /* Set the GIC as the primary interrupt controller */
-    dt_interrupt_controller = node;
-
-    /* TODO: Add check on distributor, cpu size */
-
-    printk("GIC initialization:\n"
-              "        gic_dist_addr=%"PRIpaddr"\n"
-              "        gic_cpu_addr=%"PRIpaddr"\n"
-              "        gic_hyp_addr=%"PRIpaddr"\n"
-              "        gic_vcpu_addr=%"PRIpaddr"\n"
-              "        gic_maintenance_irq=%u\n",
-              gic.dbase, gic.cbase, gic.hbase, gic.vbase,
-              gic.maintenance.irq);
-
-    if ( (gic.dbase & ~PAGE_MASK) || (gic.cbase & ~PAGE_MASK) ||
-         (gic.hbase & ~PAGE_MASK) || (gic.vbase & ~PAGE_MASK) )
-        panic("GIC interfaces not page aligned");
-
-    set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED);
-    BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) !=
-                 FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE);
-    set_fixmap(FIXMAP_GICC1, gic.cbase >> PAGE_SHIFT, DEV_SHARED);
-    if ( platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
-        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x10, DEV_SHARED);
-    else
-        set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 0x1, DEV_SHARED);
-    set_fixmap(FIXMAP_GICH, gic.hbase >> PAGE_SHIFT, DEV_SHARED);
-
-    /* Global settings: interrupt distributor */
+    gicv2_init();
     spin_lock_init(&gic_lock);
-    spin_lock(&gic_lock);
-
-    gic_dist_init();
-    gic_cpu_init();
-    gic_hyp_init();
-
-    spin_unlock(&gic_lock);
-}
-
-void send_sgi(const cpumask_t *online_mask, enum gic_sgi sgi, uint8_t irqmode)
-{
-    unsigned int mask = 0;
-
-    switch(irqmode)
-    {
-    case SGI_TARGET_OTHERS:
-        GICD[GICD_SGIR] = GICD_SGI_TARGET_OTHERS | sgi;
-        break;
-    case SGI_TARGET_SELF:
-        GICD[GICD_SGIR] = GICD_SGI_TARGET_SELF | sgi;
-        break;
-    case SGI_TARGET_LIST:
-        mask = gic_cpu_mask(online_mask);
-        GICD[GICD_SGIR] = GICD_SGI_TARGET_LIST |
-                          (mask<<GICD_SGI_TARGET_SHIFT) | sgi;
-        break;
-    default:
-         gdprintk(XENLOG_WARNING, "Wrong sgi irq mode for sgi %x\n", sgi);
-    }
 }
 
 void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi)
@@ -514,12 +278,11 @@ void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi)
 
     dsb();
 
-    send_sgi(&online_mask, sgi, SGI_TARGET_LIST);
+    gic_hw_ops->send_sgi(&online_mask, sgi, SGI_TARGET_LIST);
 }
 
 void send_SGI_one(unsigned int cpu, enum gic_sgi sgi)
 {
-    ASSERT(cpu < NR_GIC_CPU_IF);  /* Targets bitmap only supports 8 CPUs */
     send_SGI_mask(cpumask_of(cpu), sgi);
 }
 
@@ -528,8 +291,8 @@ void send_SGI_self(enum gic_sgi sgi)
     ASSERT(sgi < 16); /* There are only 16 SGIs */
 
     dsb();
-
-    send_sgi(cpumask_of(smp_processor_id()), sgi, SGI_TARGET_SELF);
+    
+    gic_hw_ops->send_sgi(cpumask_of(smp_processor_id()), sgi, SGI_TARGET_SELF);
 }
 
 void send_SGI_allbutself(enum gic_sgi sgi)
@@ -540,7 +303,7 @@ void send_SGI_allbutself(enum gic_sgi sgi)
    cpumask_andnot(&all_others_mask, &cpu_possible_map, cpumask_of(smp_processor_id()));
    dsb();
 
-   send_sgi(&all_others_mask, sgi, SGI_TARGET_OTHERS);
+   gic_hw_ops->send_sgi(&all_others_mask, sgi, SGI_TARGET_OTHERS);
 }
 
 void smp_send_state_dump(unsigned int cpu)
@@ -552,8 +315,7 @@ void smp_send_state_dump(unsigned int cpu)
 void __cpuinit gic_init_secondary_cpu(void)
 {
     spin_lock(&gic_lock);
-    gic_cpu_init();
-    gic_hyp_init();
+    gic_hw_ops->secondary_init();
     spin_unlock(&gic_lock);
 }
 
@@ -563,15 +325,14 @@ void gic_disable_cpu(void)
     ASSERT(!local_irq_is_enabled());
 
     spin_lock(&gic_lock);
-    gic_cpu_disable();
-    gic_hyp_disable();
+    gic_hw_ops->disable_interface();
     spin_unlock(&gic_lock);
 }
 
 void gic_route_ppis(void)
 {
     /* GIC maintenance */
-    gic_route_dt_irq(&gic.maintenance, cpumask_of(smp_processor_id()),
+    gic_route_dt_irq(gic_hw_ops->get_maintenance_irq(), cpumask_of(smp_processor_id()),
                      GIC_PRI_IRQ);
     /* Route timer interrupt */
     route_timer_interrupt();
@@ -646,22 +407,11 @@ int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new)
     return rc;
 }
 
-static inline void gic_set_lr(int lr, struct pending_irq *p,
+static void gic_set_lr(int lr, struct pending_irq *p,
         unsigned int state)
 {
-    uint32_t lr_reg;
-
     ASSERT(!local_irq_is_enabled());
-    BUG_ON(lr >= nr_lrs);
-    BUG_ON(lr < 0);
-    BUG_ON(state & ~(GICH_LR_STATE_MASK<<GICH_LR_STATE_SHIFT));
-
-    lr_reg = state | ((p->priority >> 3) << GICH_LR_PRIORITY_SHIFT) |
-        ((p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
-    if ( p->desc != NULL )
-        lr_reg |= GICH_LR_HW | (p->desc->irq << GICH_LR_PHYSICAL_SHIFT);
-
-    GICH[GICH_LR + lr] = lr_reg;
+    gic_hw_ops->update_lr(lr, p, state);
 
     set_bit(GIC_IRQ_GUEST_VISIBLE, &p->status);
     clear_bit(GIC_IRQ_GUEST_PENDING, &p->status);
@@ -704,6 +454,7 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
 {
     int i;
     struct pending_irq *n = irq_to_pending(v, virtual_irq);
+    unsigned int nr_lrs = gic_hw_ops->nr_lrs;
 
     ASSERT(spin_is_locked(&v->arch.vgic.lock));
 
@@ -730,27 +481,30 @@ void gic_raise_guest_irq(struct vcpu *v, unsigned int virtual_irq,
 static void gic_clear_one_lr(struct vcpu *v, int i)
 {
     struct pending_irq *p;
-    uint32_t lr;
     int irq;
+    struct gic_lr lr_val;
 
     ASSERT(spin_is_locked(&v->arch.vgic.lock));
     ASSERT(!local_irq_is_enabled());
 
-    lr = GICH[GICH_LR + i];
-    irq = (lr >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK;
+    gic_hw_ops->read_lr(i, &lr_val);
+    irq = lr_val.virq;
     p = irq_to_pending(v, irq);
-    if ( lr & GICH_LR_ACTIVE )
+    if ( lr_val.state & GICH_LR_ACTIVE )
     {
         set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
         /* HW interrupts cannot be ACTIVE and PENDING */
         if ( p->desc == NULL &&
              test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) &&
              test_and_clear_bit(GIC_IRQ_GUEST_PENDING, &p->status) )
-            GICH[GICH_LR + i] = lr | GICH_LR_PENDING;
-    } else if ( lr & GICH_LR_PENDING ) {
+        {
+                 lr_val.state |= GICH_LR_PENDING;
+                 gic_hw_ops->write_lr(i, &lr_val);
+        }
+    } else if ( lr_val.state & GICH_LR_PENDING ) {
         clear_bit(GIC_IRQ_GUEST_PENDING, &p->status);
     } else {
-        GICH[GICH_LR + i] = 0;
+        gic_hw_ops->clear_lr(i);
         clear_bit(i, &this_cpu(lr_mask));
 
         if ( p->desc != NULL )
@@ -771,6 +525,7 @@ void gic_clear_lrs(struct vcpu *v)
 {
     int i = 0;
     unsigned long flags;
+    unsigned int nr_lrs = gic_hw_ops->nr_lrs;
 
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
@@ -785,10 +540,12 @@ void gic_clear_lrs(struct vcpu *v)
 
 static void gic_restore_pending_irqs(struct vcpu *v)
 {
-    int i = 0, lrs = nr_lrs;
+    int i = 0, lrs;
     struct pending_irq *p, *t, *p_r;
     unsigned long flags;
+    unsigned int nr_lrs = gic_hw_ops->nr_lrs;
 
+    lrs = nr_lrs;
     if ( list_empty(&v->arch.vgic.lr_pending) )
         return;
 
@@ -845,13 +602,15 @@ void gic_clear_pending_irqs(struct vcpu *v)
 
 int gic_events_need_delivery(void)
 {
-    int mask_priority, lrs = nr_lrs;
+    int mask_priority, lrs;
     int max_priority = 0xff, active_priority = 0xff;
     struct vcpu *v = current;
     struct pending_irq *p;
     unsigned long flags;
+    unsigned int nr_lrs = gic_hw_ops->nr_lrs;
+    lrs = nr_lrs;
 
-    mask_priority = (GICH[GICH_VMCR] >> GICH_VMCR_PRIORITY_SHIFT) & GICH_VMCR_PRIORITY_MASK;
+    mask_priority = gic_hw_ops->read_vmcr_priority();
 
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
@@ -888,9 +647,9 @@ void gic_inject(void)
     gic_restore_pending_irqs(current);
 
     if ( !list_empty(&current->arch.vgic.lr_pending) && lr_all_full() )
-        GICH[GICH_HCR] |= GICH_HCR_UIE;
+        gic_hw_ops->update_hcr_status(GICH_HCR_UIE, 1);
     else
-        GICH[GICH_HCR] &= ~GICH_HCR_UIE;
+        gic_hw_ops->update_hcr_status(GICH_HCR_UIE, 0);
 }
 
 int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq,
@@ -941,7 +700,8 @@ out:
 static void do_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
 {
     /* Lower the priority */
-    GICC[GICC_EOIR] = sgi;
+    struct irq_desc *desc = irq_to_desc(sgi);
+    gic_hw_ops->gic_irq_ops->end(desc);
 
     switch (sgi)
     {
@@ -960,19 +720,16 @@ static void do_sgi(struct cpu_user_regs *regs, enum gic_sgi sgi)
     }
 
     /* Deactivate */
-    GICC[GICC_DIR] = sgi;
+    gic_hw_ops->deactivate_irq(sgi);
 }
 
 /* Accept an interrupt from the GIC and dispatch its handler */
 void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 {
-    uint32_t intack;
     unsigned int irq;
 
-
     do  {
-        intack = GICC[GICC_IAR];
-        irq = intack & GICC_IA_IRQ;
+        irq = gic_hw_ops->ack_irq();
 
         if ( likely(irq >= 16 && irq < 1021) )
         {
@@ -994,49 +751,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
 
 int gicv_setup(struct domain *d)
 {
-    int ret;
-
-    /*
-     * Domain 0 gets the hardware address.
-     * Guests get the virtual platform layout.
-     */
-    if ( d->domain_id == 0 )
-    {
-        d->arch.vgic.dbase = gic.dbase;
-        d->arch.vgic.cbase = gic.cbase;
-    }
-    else
-    {
-        d->arch.vgic.dbase = GUEST_GICD_BASE;
-        d->arch.vgic.cbase = GUEST_GICC_BASE;
-    }
-
-    d->arch.vgic.nr_lines = 0;
-
-    /*
-     * Map the gic virtual cpu interface in the gic cpu interface
-     * region of the guest.
-     *
-     * The second page is always mapped at +4K irrespective of the
-     * GIC_64K_STRIDE quirk. The DTB passed to the guest reflects this.
-     */
-    ret = map_mmio_regions(d, d->arch.vgic.cbase,
-                           d->arch.vgic.cbase + PAGE_SIZE - 1,
-                           gic.vbase);
-    if (ret)
-        return ret;
-
-    if ( !platform_has_quirk(PLATFORM_QUIRK_GIC_64K_STRIDE) )
-        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
-                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
-                               gic.vbase + PAGE_SIZE);
-    else
-        ret = map_mmio_regions(d, d->arch.vgic.cbase + PAGE_SIZE,
-                               d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1,
-                               gic.vbase + 16*PAGE_SIZE);
-
-    return ret;
-
+    return gic_hw_ops->gicv_setup(d);
 }
 
 static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
@@ -1051,18 +766,10 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
 
 void gic_dump_info(struct vcpu *v)
 {
-    int i;
     struct pending_irq *p;
 
     printk("GICH_LRs (vcpu %d) mask=%"PRIx64"\n", v->vcpu_id, v->arch.lr_mask);
-    if ( v == current )
-    {
-        for ( i = 0; i < nr_lrs; i++ )
-            printk("   HW_LR[%d]=%x\n", i, GICH[GICH_LR + i]);
-    } else {
-        for ( i = 0; i < nr_lrs; i++ )
-            printk("   VCPU_LR[%d]=%x\n", i, v->arch.gic_lr[i]);
-    }
+    gic_hw_ops->dump_state(v);
 
     list_for_each_entry ( p, &v->arch.vgic.inflight_irqs, inflight )
     {
@@ -1078,7 +785,7 @@ void gic_dump_info(struct vcpu *v)
 
 void __cpuinit init_maintenance_interrupt(void)
 {
-    request_dt_irq(&gic.maintenance, maintenance_interrupt,
+    request_dt_irq(gic_hw_ops->get_maintenance_irq(), maintenance_interrupt,
                    "irq-maintenance", NULL);
 }
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index eba41ee..2387e38 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -43,12 +43,41 @@
 #define SGI_TARGET_OTHERS  1
 #define SGI_TARGET_SELF    2
 
+#define GICH_LR_PENDING    1
+#define GICH_LR_ACTIVE     2
+
+#define GICH_HCR_EN       (1 << 0)
+#define GICH_HCR_UIE      (1 << 1)
+#define GICH_HCR_LRENPIE  (1 << 2)
+#define GICH_HCR_NPIE     (1 << 3)
+#define GICH_HCR_VGRP0EIE (1 << 4)
+#define GICH_HCR_VGRP0DIE (1 << 5)
+#define GICH_HCR_VGRP1EIE (1 << 6)
+#define GICH_HCR_VGRP1DIE (1 << 7)
+
 #ifndef __ASSEMBLY__
 #include <xen/device_tree.h>
+#include <xen/irq.h>
 
 #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
                         DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")
 
+/*
+ * Decode LR register content and populate below struct.
+ * The LR register format is different for GIC HW version
+ */
+struct gic_lr {
+   uint32_t pirq;
+   uint32_t virq;
+   uint8_t priority;
+   uint8_t state;
+   uint8_t hw_status;
+   uint8_t grp;
+};
+
+extern int gic_hw_version(void);
+extern void gicv2_init(void);
+
 extern int domain_vgic_init(struct domain *d);
 extern void domain_vgic_free(struct domain *d);
 
@@ -114,6 +143,63 @@ int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
                   unsigned int *out_hwirq, unsigned int *out_type);
 void gic_clear_lrs(struct vcpu *v);
 
+enum gic_version {
+    GIC_V2 = 2,
+};
+
+struct gic_hw_operations {
+    /* GIC version */
+    enum gic_version hw_version;
+    /* Number of GIC lines supported */
+    unsigned int nr_lines;
+    /* Number of LR registers */
+    unsigned int nr_lrs;
+    /* Maintenance irq is derived from dt node. Fetch from gic driver */
+    struct dt_irq * (*get_maintenance_irq)(void);
+    /* Save GIC registers */
+    void (*save_state)(struct vcpu *);
+    /* Restore GIC registers */
+    void (*restore_state)(struct vcpu *);
+    /* Dump GIC LR register information */
+    void (*dump_state)(struct vcpu *);
+    /* Map MMIO region of GIC and get GIC address information */
+    int (*gicv_setup)(struct domain *);
+
+    /* hw_irq_controller for enable/disable/eoi irq */
+    hw_irq_controller *gic_irq_ops;
+
+    /* Deactivate/reduce priority of irq */
+    void (*deactivate_irq)(int);
+    /* Ack IRQ and return irq id */
+    unsigned int (*ack_irq)(void);
+    /* Set IRQ property */
+    void (*set_irq_property)(unsigned int irq, bool_t level,
+                            const cpumask_t *cpu_mask,
+                            unsigned int priority);
+    /* Send SGI */
+    void (*send_sgi)(const cpumask_t *online_mask,
+                         enum gic_sgi sgi, uint8_t irqmode);
+    /* Disable CPU physical and virtual interfaces */
+    void (*disable_interface)(void);
+    /* Update LR with state and priority */
+    void (*update_lr)(int lr, struct pending_irq *, unsigned int state);
+    /* Update HCR status register */
+    void (*update_hcr_status)(uint32_t flag, bool_t set);
+    /* Clear LR register */
+    void (*clear_lr)(int lr);
+    /* Read LR register and populate gic_lr structure */
+    void (*read_lr)(int lr, struct gic_lr *);
+    /* Write LR register from gic_lr structure */
+    void (*write_lr)(int lr, struct gic_lr *);
+    /* Read VMCR priority */
+    unsigned int (*read_vmcr_priority)(void);
+    /* Secondary CPU init */
+    void (*secondary_init)(void);
+};
+
+void register_gic_ops(const struct gic_hw_operations *ops);
+extern void update_cpu_lr_mask(void);
+
 #endif /* __ASSEMBLY__ */
 #endif
 
diff --git a/xen/include/asm-arm/gic_v2_defs.h b/xen/include/asm-arm/gic_v2_defs.h
index 033d826..cb47edd 100644
--- a/xen/include/asm-arm/gic_v2_defs.h
+++ b/xen/include/asm-arm/gic_v2_defs.h
@@ -96,15 +96,6 @@
 #define GICC_IA_CPU_MASK  0x1c00
 #define GICC_IA_CPU_SHIFT 10
 
-#define GICH_HCR_EN       (1 << 0)
-#define GICH_HCR_UIE      (1 << 1)
-#define GICH_HCR_LRENPIE  (1 << 2)
-#define GICH_HCR_NPIE     (1 << 3)
-#define GICH_HCR_VGRP0EIE (1 << 4)
-#define GICH_HCR_VGRP0DIE (1 << 5)
-#define GICH_HCR_VGRP1EIE (1 << 6)
-#define GICH_HCR_VGRP1DIE (1 << 7)
-
 #define GICH_MISR_EOI     (1 << 0)
 #define GICH_MISR_U       (1 << 1)
 #define GICH_MISR_LRENP   (1 << 2)
@@ -121,9 +112,12 @@
 #define GICH_LR_STATE_MASK      0x3
 #define GICH_LR_STATE_SHIFT     28
 #define GICH_LR_PRIORITY_SHIFT  23
+#define GICH_LR_PRIORITY_MASK   0x1f
+#define GICH_LR_HW_SHIFT        31
+#define GICH_LR_HW_MASK         0x1
+#define GICH_LR_GRP_SHIFT       30
+#define GICH_LR_GRP_MASK        0x1
 #define GICH_LR_MAINTENANCE_IRQ (1<<19)
-#define GICH_LR_PENDING         (1<<28)
-#define GICH_LR_ACTIVE          (1<<29)
 #define GICH_LR_GRP1            (1<<30)
 #define GICH_LR_HW              (1<<31)
 #define GICH_LR_CPUID_SHIFT     9
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (6 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 18:41   ` Julien Grall
  2014-04-23 14:58   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 09/16] xen/arm: use device api to detect GIC version vijay.kilari
                   ` (7 subsequent siblings)
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

GIC specific context data structure that saves and restores
GIC  registers are moved to gic.h from domain.h
The structure is converted to union so that we can
add version specific structure to this union for
later GIC versions.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v2.c        |   14 +++++++-------
 xen/include/asm-arm/domain.h |    4 ++--
 xen/include/asm-arm/gic.h    |   10 ++++++++++
 3 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 0c0fa86..7c63bae 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -89,9 +89,9 @@ static void gicv2_save_state(struct vcpu *v)
      * accessed simultaneously by another pCPU.
      */
     for ( i = 0; i < nr_lrs; i++ )
-        v->arch.gic_lr[i] = GICH[GICH_LR + i];
-    v->arch.gic_apr = GICH[GICH_APR];
-    v->arch.gic_vmcr = GICH[GICH_VMCR];
+        v->arch.gic.v2.lr[i] = GICH[GICH_LR + i];
+    v->arch.gic.v2.apr = GICH[GICH_APR];
+    v->arch.gic.v2.vmcr = GICH[GICH_VMCR];
     /* Disable until next VCPU scheduled */
     GICH[GICH_HCR] = 0;
 }
@@ -101,9 +101,9 @@ static void gicv2_restore_state(struct vcpu *v)
     int i;
 
     for ( i = 0; i < nr_lrs; i++ )
-        GICH[GICH_LR + i] = v->arch.gic_lr[i];
-    GICH[GICH_APR] = v->arch.gic_apr;
-    GICH[GICH_VMCR] = v->arch.gic_vmcr;
+        GICH[GICH_LR + i] = v->arch.gic.v2.lr[i];
+    GICH[GICH_APR] = v->arch.gic.v2.apr;
+    GICH[GICH_VMCR] = v->arch.gic.v2.vmcr;
     GICH[GICH_HCR] = GICH_HCR_EN;
 }
 
@@ -116,7 +116,7 @@ static void gicv2_dump_state(struct vcpu *v)
             printk("   HW_LR[%d]=%x\n", i, GICH[GICH_LR + i]);
     } else {
         for ( i = 0; i < nr_lrs; i++ )
-            printk("   VCPU_LR[%d]=%x\n", i, v->arch.gic_lr[i]);
+            printk("   VCPU_LR[%d]=%x\n", i, v->arch.gic.v2.lr[i]);
     }
 }
 
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 999bbdd..be1b084 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -8,6 +8,7 @@
 #include <asm/p2m.h>
 #include <asm/vfp.h>
 #include <asm/mmio.h>
+#include <asm/gic.h>
 #include <public/hvm/params.h>
 #include <xen/serial.h>
 
@@ -260,8 +261,7 @@ struct arch_vcpu
     uint32_t csselr;
     register_t vmpidr;
 
-    uint32_t gic_hcr, gic_vmcr, gic_apr;
-    uint32_t gic_lr[64];
+    union gic_state_data gic;
     uint64_t event_mask;
     uint64_t lr_mask;
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 2387e38..42f0e79 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -62,6 +62,16 @@
 #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
                         DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")
 
+struct gic_v2 {
+    uint32_t hcr, vmcr;
+    uint32_t apr;
+    uint32_t lr[64];
+};
+
+union gic_state_data {
+    struct gic_v2 v2;
+};
+
 /*
  * Decode LR register content and populate below struct.
  * The LR register format is different for GIC HW version
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 09/16] xen/arm: use device api to detect GIC version
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (7 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 18:49   ` Julien Grall
  2014-04-23 15:01   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file vijay.kilari
                   ` (6 subsequent siblings)
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Run through the device tree to detect
compatible GIC version and initialize GIC driver

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v2.c        |   26 +++++++++++++++-----------
 xen/arch/arm/gic.c           |   24 +++++++++++++++++++++++-
 xen/include/asm-arm/device.h |    3 ++-
 xen/include/asm-arm/gic.h    |    1 -
 4 files changed, 40 insertions(+), 14 deletions(-)

diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 7c63bae..1e62dd9 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -31,6 +31,7 @@
 #include <asm/p2m.h>
 #include <asm/domain.h>
 #include <asm/platform.h>
+#include <asm/device.h>
 
 #include <asm/gic_v2_defs.h>
 #include <asm/gic.h>
@@ -276,20 +277,10 @@ static void __cpuinit gicv2_hyp_disable(void)
 }
 
 /* Set up the GIC */
-void __init gicv2_init(void)
+int __init gicv2_init(struct dt_device_node *node, const void *data)
 {
-    static const struct dt_device_match gic_ids[] __initconst =
-    {
-        DT_MATCH_GIC,
-        { /* sentinel */ },
-    };
-    struct dt_device_node *node;
     int res;
 
-    node = dt_find_interrupt_controller(gic_ids);
-    if ( !node )
-        panic("Unable to find compatible GIC in the device tree");
-
     dt_device_set_used_by(node, DOMID_XEN);
 
     res = dt_device_get_address(node, 0, &gic.dbase, NULL);
@@ -348,6 +339,7 @@ void __init gicv2_init(void)
 
     gic_ops.hw_version = GIC_V2;
     register_gic_ops(&gic_ops);
+    return 0;
 }
 
 static void gicv2_secondary_cpu_init(void)
@@ -522,6 +514,18 @@ static struct gic_hw_operations gic_ops = {
     .read_vmcr_priority  = gicv2_read_vmcr_priority,
 };
 
+static const char * const gicv2_dt_compat[] __initconst =
+{
+    "arm,cortex-a15-gic",
+    "arm,cortex-a9-gic",
+    NULL
+};
+
+DT_DEVICE_START(gicv2, "GIC", DEVICE_GIC)
+        .compatible = gicv2_dt_compat,
+        .init = gicv2_init,
+DT_DEVICE_END
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index ce21ef6..4a86c42 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -31,6 +31,7 @@
 #include <asm/p2m.h>
 #include <asm/domain.h>
 #include <asm/platform.h>
+#include <asm/device.h>
 
 #include <asm/gic.h>
 
@@ -264,8 +265,29 @@ int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
 /* Set up the GIC */
 void __init gic_init(void)
 {
-    gicv2_init();
+    int rc;
+    struct dt_device_node *node;
+    uint8_t num_gics = 0;
+
     spin_lock_init(&gic_lock);
+
+    dt_for_each_device_node(dt_host, node)
+    {
+        if ( !dt_get_property(node, "interrupt-controller", NULL) )
+            continue;
+
+        if ( !dt_get_parent(node) )
+            continue;
+
+        rc = device_init(node, DEVICE_GIC, NULL);
+        if ( !rc )
+        {
+            num_gics++;
+            break;
+        }
+    }
+    if ( !num_gics )
+        panic("Unable to find compatible GIC in the device tree");
 }
 
 void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi)
diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h
index 9e47ca6..61412e6 100644
--- a/xen/include/asm-arm/device.h
+++ b/xen/include/asm-arm/device.h
@@ -6,7 +6,8 @@
 
 enum device_type
 {
-    DEVICE_SERIAL
+    DEVICE_SERIAL,
+    DEVICE_GIC
 };
 
 struct device_desc {
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 42f0e79..2209f14 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -86,7 +86,6 @@ struct gic_lr {
 };
 
 extern int gic_hw_version(void);
-extern void gicv2_init(void);
 
 extern int domain_vgic_init(struct domain *d);
 extern void domain_vgic_free(struct domain *d);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (8 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 09/16] xen/arm: use device api to detect GIC version vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 19:10   ` Julien Grall
  2014-05-07 15:03   ` Julien Grall
  2014-04-15 11:17 ` [PATCH v3 11/16] xen/arm: move vgic defines to vgic " vijay.kilari
                   ` (5 subsequent siblings)
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

vgic_irq_rank structure contains gic specific data elements.
Move this out of domain.h to new vgic header file vgic.h
Allocate memory dynamically in vgic driver. This patch reduces
the size of domain struct which helps to accomodate future GIC
hw versions.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/domain.c        |    2 ++
 xen/arch/arm/vgic.c          |   20 ++++++++++++++++----
 xen/include/asm-arm/domain.h |   11 +----------
 xen/include/asm-arm/vgic.h   |   40 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 59 insertions(+), 14 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 0d52457..ef577d7 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -31,6 +31,7 @@
 #include <asm/procinfo.h>
 
 #include <asm/gic.h>
+#include <asm/vgic.h>
 #include <asm/platform.h>
 #include "vtimer.h"
 #include "vuart.h"
@@ -494,6 +495,7 @@ int vcpu_initialise(struct vcpu *v)
 void vcpu_destroy(struct vcpu *v)
 {
     vcpu_timer_destroy(v);
+    vcpu_vgic_free(v);
     free_xenheap_pages(v->arch.stack, STACK_ORDER);
 }
 
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 4830b5d..f73247d 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -30,6 +30,7 @@
 #include <asm/mmio.h>
 #include <asm/gic_v2_defs.h>
 #include <asm/gic.h>
+#include <asm/vgic.h>
 
 #define REG(n) (n/4)
 
@@ -69,7 +70,7 @@ static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
     int rank = REG_RANK_NR(b, n);
 
     if ( rank == 0 )
-        return &v->arch.vgic.private_irqs;
+        return v->arch.vgic.private_irqs;
     else if ( rank <= DOMAIN_NR_RANKS(v->domain) )
         return &v->domain->arch.vgic.shared_irqs[rank - 1];
     else
@@ -117,9 +118,14 @@ void domain_vgic_free(struct domain *d)
 int vcpu_vgic_init(struct vcpu *v)
 {
     int i;
-    memset(&v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
 
-    spin_lock_init(&v->arch.vgic.private_irqs.lock);
+    v->arch.vgic.private_irqs = xzalloc(struct vgic_irq_rank);
+    if ( v->arch.vgic.private_irqs == NULL )
+      return -ENOMEM;
+
+    memset(v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
+
+    spin_lock_init(&v->arch.vgic.private_irqs->lock);
 
     memset(&v->arch.vgic.pending_irqs, 0, sizeof(v->arch.vgic.pending_irqs));
     for (i = 0; i < 32; i++)
@@ -130,7 +136,7 @@ int vcpu_vgic_init(struct vcpu *v)
 
     /* For SGI and PPI the target is always this CPU */
     for ( i = 0 ; i < 8 ; i++ )
-        v->arch.vgic.private_irqs.itargets[i] =
+        v->arch.vgic.private_irqs->itargets[i] =
               (1<<(v->vcpu_id+0))
             | (1<<(v->vcpu_id+8))
             | (1<<(v->vcpu_id+16))
@@ -142,6 +148,12 @@ int vcpu_vgic_init(struct vcpu *v)
     return 0;
 }
 
+int vcpu_vgic_free(struct vcpu *v)
+{
+    xfree(v->arch.vgic.private_irqs);
+    return 0;
+}
+
 #define vgic_lock(v)   spin_lock_irq(&(v)->domain->arch.vgic.lock)
 #define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock)
 
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index be1b084..ccd9640 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -12,15 +12,6 @@
 #include <public/hvm/params.h>
 #include <xen/serial.h>
 
-/* Represents state corresponding to a block of 32 interrupts */
-struct vgic_irq_rank {
-    spinlock_t lock; /* Covers access to all other members of this struct */
-    uint32_t ienable, iactive, ipend, pendsgi;
-    uint32_t icfg[2];
-    uint32_t ipriority[8];
-    uint32_t itargets[8];
-};
-
 struct pending_irq
 {
     /*
@@ -271,7 +262,7 @@ struct arch_vcpu
          * struct arch_domain.
          */
         struct pending_irq pending_irqs[32];
-        struct vgic_irq_rank private_irqs;
+        struct vgic_irq_rank *private_irqs;
 
         /* This list is ordered by IRQ priority and it is used to keep
          * track of the IRQs that the VGIC injected into the guest.
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
new file mode 100644
index 0000000..104a87d
--- /dev/null
+++ b/xen/include/asm-arm/vgic.h
@@ -0,0 +1,40 @@
+/*
+ * ARM Virtual Generic Interrupt Controller support
+ *
+ * Ian Campbell <ian.campbell@citrix.com>
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARM_VGIC_H__
+#define __ASM_ARM_VGIC_H__
+
+/* Represents state corresponding to a block of 32 interrupts */
+struct vgic_irq_rank {
+    spinlock_t lock; /* Covers access to all other members of this struct */
+    uint32_t ienable, iactive, ipend, pendsgi;
+    uint32_t icfg[2];
+    uint32_t ipriority[8];
+    uint32_t itargets[8];
+};
+
+extern int vcpu_vgic_free(struct vcpu *v);
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 11/16] xen/arm: move vgic defines to vgic header file
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (9 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-16 17:01   ` Julien Grall
  2014-04-15 11:17 ` [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver vijay.kilari
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

gic.h contains defines of vgic. Move these to vgic
header file. Also move inline functions and defines
in vgic.c to vgic.h

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/irq.c         |    1 +
 xen/arch/arm/time.c        |    1 +
 xen/arch/arm/vgic.c        |   41 --------------------------------------
 xen/arch/arm/vpsci.c       |    1 +
 xen/arch/arm/vtimer.c      |    1 +
 xen/include/asm-arm/gic.h  |   10 +---------
 xen/include/asm-arm/vgic.h |   47 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 52 insertions(+), 50 deletions(-)

diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 5daa269..4686c85 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -26,6 +26,7 @@
 #include <xen/sched.h>
 
 #include <asm/gic.h>
+#include <asm/vgic.h>
 
 static void enable_none(struct irq_desc *irq) { }
 static unsigned int startup_none(struct irq_desc *irq) { return 0; }
diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index ae09c6b..953b0b0 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -32,6 +32,7 @@
 #include <asm/system.h>
 #include <asm/time.h>
 #include <asm/gic.h>
+#include <asm/vgic.h>
 #include <asm/cpufeature.h>
 #include <asm/platform.h>
 
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index f73247d..7e258ae 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -34,28 +34,9 @@
 
 #define REG(n) (n/4)
 
-/* Number of ranks of interrupt registers for a domain */
-#define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
-
 static struct mmio_handler vgic_distr_mmio_handler;
 
 /*
- * Rank containing GICD_<FOO><n> for GICD_<FOO> with
- * <b>-bits-per-interrupt
- */
-static inline int REG_RANK_NR(int b, uint32_t n)
-{
-    switch ( b )
-    {
-    case 8: return n >> 3;
-    case 4: return n >> 2;
-    case 2: return n >> 1;
-    case 1: return n;
-    default: BUG();
-    }
-}
-
-/*
  * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
  * <b>-bits-per-interrupt.
  */
@@ -154,12 +135,6 @@ int vcpu_vgic_free(struct vcpu *v)
     return 0;
 }
 
-#define vgic_lock(v)   spin_lock_irq(&(v)->domain->arch.vgic.lock)
-#define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock)
-
-#define vgic_lock_rank(v, r) spin_lock(&(r)->lock)
-#define vgic_unlock_rank(v, r) spin_unlock(&(r)->lock)
-
 static uint32_t byte_read(uint32_t val, int sign, int offset)
 {
     int byte = offset & 0x3;
@@ -425,22 +400,6 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
     }
 }
 
-static inline int is_vcpu_running(struct domain *d, int vcpuid)
-{
-    struct vcpu *v;
-
-    if ( vcpuid >= d->max_vcpus )
-        return 0;
-
-    v = d->vcpu[vcpuid];
-    if ( v == NULL )
-        return 0;
-    if (test_bit(_VPF_down, &v->pause_flags) )
-        return 0;
-
-    return 1;
-}
-
 static int vgic_to_sgi(struct vcpu *v, register_t sgir)
 {
     struct domain *d = v->domain;
diff --git a/xen/arch/arm/vpsci.c b/xen/arch/arm/vpsci.c
index c82884f..37e6a55 100644
--- a/xen/arch/arm/vpsci.c
+++ b/xen/arch/arm/vpsci.c
@@ -16,6 +16,7 @@
 
 #include <asm/current.h>
 #include <asm/gic.h>
+#include <asm/vgic.h>
 #include <asm/psci.h>
 
 int do_psci_cpu_on(uint32_t vcpuid, register_t entry_point)
diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c
index 87be11e..4755e1a 100644
--- a/xen/arch/arm/vtimer.c
+++ b/xen/arch/arm/vtimer.c
@@ -24,6 +24,7 @@
 #include <asm/irq.h>
 #include <asm/time.h>
 #include <asm/gic.h>
+#include <asm/vgic.h>
 #include <asm/regs.h>
 
 extern s_time_t ticks_to_ns(uint64_t ticks);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 2209f14..7489684 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -85,16 +85,8 @@ struct gic_lr {
    uint8_t grp;
 };
 
-extern int gic_hw_version(void);
-
-extern int domain_vgic_init(struct domain *d);
-extern void domain_vgic_free(struct domain *d);
-
-extern int vcpu_vgic_init(struct vcpu *v);
-
-extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq);
-extern void vgic_clear_pending_irqs(struct vcpu *v);
 extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq);
+extern int gic_hw_version(void);
 
 /* Program the GIC to route an interrupt with a dt_irq */
 extern void gic_route_dt_irq(const struct dt_irq *irq,
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 104a87d..f9d6549 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -17,6 +17,7 @@
 
 #ifndef __ASM_ARM_VGIC_H__
 #define __ASM_ARM_VGIC_H__
+#include <xen/bitops.h>
 
 /* Represents state corresponding to a block of 32 interrupts */
 struct vgic_irq_rank {
@@ -27,6 +28,52 @@ struct vgic_irq_rank {
     uint32_t itargets[8];
 };
 
+/* Number of ranks of interrupt registers for a domain */
+#define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
+
+#define vgic_lock(v)   spin_lock_irq(&(v)->domain->arch.vgic.lock)
+#define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock)
+
+#define vgic_lock_rank(v, r) spin_lock(&(r)->lock)
+#define vgic_unlock_rank(v, r) spin_unlock(&(r)->lock)
+
+/*
+ * Rank containing GICD_<FOO><n> for GICD_<FOO> with
+ * <b>-bits-per-interrupt
+ */
+static inline int REG_RANK_NR(int b, uint32_t n)
+{
+    switch ( b )
+    {
+    case 8: return n >> 3;
+    case 4: return n >> 2;
+    case 2: return n >> 1;
+    case 1: return n;
+    default: BUG();
+    }
+}
+
+static inline int is_vcpu_running(struct domain *d, int vcpuid)
+{
+    struct vcpu *v;
+
+    if ( vcpuid >= d->max_vcpus )
+        return 0;
+
+    v = d->vcpu[vcpuid];
+    if ( v == NULL )
+        return 0;
+    if (test_bit(_VPF_down, &v->pause_flags) )
+        return 0;
+
+    return 1;
+}
+
+extern int domain_vgic_init(struct domain *d);
+extern void domain_vgic_free(struct domain *d);
+extern int vcpu_vgic_init(struct vcpu *v);
+extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq);
+extern void vgic_clear_pending_irqs(struct vcpu *v);
 extern int vcpu_vgic_free(struct vcpu *v);
 #endif
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (10 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 11/16] xen/arm: move vgic defines to vgic " vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 20:05   ` Julien Grall
  2014-04-23 15:12   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 13/16] xen/arm: Add support for GIC v3 vijay.kilari
                   ` (3 subsequent siblings)
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Existing vGIC driver has both generic code and hw specific
code. Segregate vGIC low level driver into vgic-v2.c and
keep generic code in existing vgic.c file

some static generic functions in vgic.c is made as non-static
so that these generic functions can be used in vGIC v2 driver.

vGIC v2 driver registers required callbacks to generic vGIC
driver. This helps to plug in next version of vGIC drivers
like vGIC v3

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/Makefile      |    2 +-
 xen/arch/arm/vgic-v2.c     |  540 ++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic.c        |  516 ++++--------------------------------------
 xen/include/asm-arm/vgic.h |   15 ++
 4 files changed, 595 insertions(+), 478 deletions(-)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 969ee52..20f59f4 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -26,7 +26,7 @@ obj-y += smpboot.o
 obj-y += smp.o
 obj-y += shutdown.o
 obj-y += traps.o
-obj-y += vgic.o
+obj-y += vgic.o vgic-v2.o
 obj-y += vtimer.o
 obj-y += vuart.o
 obj-y += hvm.o
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
new file mode 100644
index 0000000..12d9645
--- /dev/null
+++ b/xen/arch/arm/vgic-v2.c
@@ -0,0 +1,540 @@
+/*
+ * xen/arch/arm/vgic-v2.c
+ *
+ * ARM Virtual Generic Interrupt Controller support v2
+ *
+ * Ian Campbell <ian.campbell@citrix.com>
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/bitops.h>
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/softirq.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+
+#include <asm/current.h>
+#include <asm/device.h>
+
+#include <asm/mmio.h>
+#include <asm/gic_v2_defs.h>
+#include <asm/gic.h>
+#include <asm/vgic.h>
+
+#define REG(n) (n/4)
+
+/*
+ * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
+ * <b>-bits-per-interrupt.
+ */
+#define REG_RANK_INDEX(b, n) ((n) & ((b)-1))
+
+/*
+ * Returns rank corresponding to a GICD_<FOO><n> register for
+ * GICD_<FOO> with <b>-bits-per-interrupt.
+ */
+static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
+{
+    int rank = REG_RANK_NR(b, n);
+    return vgic_get_irqrank(v, rank);
+}
+
+static int vgic_read_priority(struct vcpu *v, int irq)
+{
+   int idx = irq >> 2;
+   struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx);
+   return byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, irq & 0x3);
+}
+
+static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    struct vgic_irq_rank *rank;
+    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
+    int gicd_reg = REG(offset);
+
+    switch ( gicd_reg )
+    {
+    case GICD_CTLR:
+        if ( dabt.size != 2 ) goto bad_width;
+        vgic_lock(v);
+        *r = v->domain->arch.vgic.ctlr;
+        vgic_unlock(v);
+        return 1;
+    case GICD_TYPER:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* No secure world support for guests. */
+        vgic_lock(v);
+        *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS )
+            |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES );
+        vgic_unlock(v);
+        return 1;
+    case GICD_IIDR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /*
+         * XXX Do we need a JEP106 manufacturer ID?
+         * Just use the physical h/w value for now
+         */
+        *r = 0x0000043b;
+        return 1;
+
+    /* Implementation defined -- read as zero */
+    case REG(0x020) ... REG(0x03c):
+        goto read_as_zero;
+
+    case GICD_IGROUPR ... GICD_IGROUPRN:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+
+    case GICD_ISENABLER ... GICD_ISENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ICENABLER ... GICD_ICENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ISPENDR ... GICD_ISPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISPENDR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->ipend, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ICPENDR ... GICD_ICPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICPENDR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->ipend, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ISACTIVER ... GICD_ISACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ICACTIVER ... GICD_ICACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ITARGETSR ... GICD_ITARGETSRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
+        if ( rank == NULL) goto read_as_zero;
+
+        vgic_lock_rank(v, rank);
+        *r = rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)];
+        if ( dabt.size == 0 )
+            *r = byte_read(*r, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
+        if ( rank == NULL) goto read_as_zero;
+
+        vgic_lock_rank(v, rank);
+        *r = rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)];
+        if ( dabt.size == 0 )
+            *r = byte_read(*r, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ICFGR ... GICD_ICFGRN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)];
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_NSACR ... GICD_NSACRN:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+
+    case GICD_SGIR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* Write only -- read unknown */
+        *r = 0xdeadbeef;
+        return 1;
+
+    case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_CPENDSGIR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->pendsgi, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_SPENDSGIR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->pendsgi, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    /* Implementation defined -- read as zero */
+    case REG(0xfd0) ... REG(0xfe4):
+        goto read_as_zero;
+
+    case GICD_ICPIDR2:
+        if ( dabt.size != 2 ) goto bad_width;
+        printk("vGICD: unhandled read from ICPIDR2\n");
+        return 0;
+
+    /* Implementation defined -- read as zero */
+    case REG(0xfec) ... REG(0xffc):
+        goto read_as_zero;
+
+    /* Reserved -- read as zero */
+    case REG(0x00c) ... REG(0x01c):
+    case REG(0x040) ... REG(0x07c):
+    case REG(0x7fc):
+    case REG(0xbfc):
+    case REG(0xf04) ... REG(0xf0c):
+    case REG(0xf30) ... REG(0xfcc):
+        goto read_as_zero;
+
+    default:
+        printk("vGICD: unhandled read r%d offset %#08x\n",
+               dabt.reg, offset);
+        return 0;
+    }
+
+bad_width:
+    printk("vGICD: bad read width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, offset);
+    domain_crash_synchronous();
+    return 0;
+
+read_as_zero:
+    if ( dabt.size != 2 ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int vgic_to_sgi(struct vcpu *v, register_t sgir)
+{
+    struct domain *d = v->domain;
+    int virtual_irq;
+    int filter;
+    int vcpuid;
+    int i;
+    unsigned long vcpu_mask = 0;
+
+    ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));
+
+    filter = (sgir & GICD_SGI_TARGET_LIST_MASK);
+    virtual_irq = (sgir & GICD_SGI_INTID_MASK);
+    ASSERT( virtual_irq < 16 );
+
+    switch ( filter )
+    {
+    case GICD_SGI_TARGET_LIST:
+        vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT;
+        break;
+    case GICD_SGI_TARGET_OTHERS:
+        for ( i = 0; i < d->max_vcpus; i++ )
+        {
+            if ( i != current->vcpu_id && is_vcpu_running(d, i) )
+                set_bit(i, &vcpu_mask);
+        }
+        break;
+    case GICD_SGI_TARGET_SELF:
+        set_bit(current->vcpu_id, &vcpu_mask);
+        break;
+    default:
+        gdprintk(XENLOG_WARNING, "vGICD: unhandled GICD_SGIR write \
+                 %"PRIregister" with wrong TargetListFilter field\n", sgir);
+            return 0;
+    }
+
+    for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus )
+    {
+        if ( !is_vcpu_running(d, vcpuid) )
+        {
+            gdprintk(XENLOG_WARNING, "vGICD: GICD_SGIR write \
+                     r=%"PRIregister" vcpu_mask=%lx, wrong CPUTargetList\n",
+                     sgir, vcpu_mask);
+            continue;
+        }
+        vgic_vcpu_inject_irq(d->vcpu[vcpuid], virtual_irq);
+    }
+    return 1;
+}
+
+static int vgic_distr_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    struct vgic_irq_rank *rank;
+    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
+    int gicd_reg = REG(offset);
+    uint32_t tr;
+
+    switch ( gicd_reg )
+    {
+    case GICD_CTLR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* Ignore all but the enable bit */
+        v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE;
+        return 1;
+
+    /* R/O -- write ignored */
+    case GICD_TYPER:
+    case GICD_IIDR:
+        goto write_ignore;
+
+    /* Implementation defined -- write ignored */
+    case REG(0x020) ... REG(0x03c):
+        goto write_ignore;
+
+    case GICD_IGROUPR ... GICD_IGROUPRN:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+
+    case GICD_ISENABLER ... GICD_ISENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        tr = rank->ienable;
+        rank->ienable |= *r;
+        vgic_unlock_rank(v, rank);
+        vgic_enable_irqs(v, (*r) & (~tr), gicd_reg - GICD_ISENABLER);
+        return 1;
+
+    case GICD_ICENABLER ... GICD_ICENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        tr = rank->ienable;
+        rank->ienable &= ~*r;
+        vgic_unlock_rank(v, rank);
+        vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER);
+        return 1;
+
+    case GICD_ISPENDR ... GICD_ISPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDR%d\n",
+               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ISPENDR);
+        return 0;
+
+    case GICD_ICPENDR ... GICD_ICPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDR%d\n",
+               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ICPENDR);
+        return 0;
+
+    case GICD_ISACTIVER ... GICD_ISACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ICACTIVER ... GICD_ICACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ITARGETSR ... GICD_ITARGETSR + 7:
+        /* SGI/PPI target is read only */
+        goto write_ignore;
+
+    case GICD_ITARGETSR + 8 ... GICD_ITARGETSRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        if ( dabt.size == 2 )
+            rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)] = *r;
+        else
+            byte_write(&rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)],
+                       *r, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        if ( dabt.size == 2 )
+            rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)] = *r;
+        else
+            byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)],
+                       *r, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_ICFGR: /* SGIs */
+        goto write_ignore;
+    case GICD_ICFGR + 1: /* PPIs */
+        /* It is implementation defined if these are writeable. We chose not */
+        goto write_ignore;
+    case GICD_ICFGR + 2 ... GICD_ICFGRN: /* SPIs */
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
+        vgic_lock_rank(v, rank);
+        if ( rank == NULL) goto write_ignore;
+        rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)] = *r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+
+    case GICD_NSACR ... GICD_NSACRN:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+
+    case GICD_SGIR:
+        if ( dabt.size != 2 )
+            goto bad_width;
+        return vgic_to_sgi(v, *r);
+
+    case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDSGIR%d\n",
+               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_CPENDSGIR);
+        return 0;
+
+    case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDSGIR%d\n",
+               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_SPENDSGIR);
+        return 0;
+
+    /* Implementation defined -- write ignored */
+    case REG(0xfd0) ... REG(0xfe4):
+        goto write_ignore;
+
+    /* R/O -- write ignore */
+    case GICD_ICPIDR2:
+        goto write_ignore;
+
+    /* Implementation defined -- write ignored */
+    case REG(0xfec) ... REG(0xffc):
+        goto write_ignore;
+
+    /* Reserved -- write ignored */
+    case REG(0x00c) ... REG(0x01c):
+    case REG(0x040) ... REG(0x07c):
+    case REG(0x7fc):
+    case REG(0xbfc):
+    case REG(0xf04) ... REG(0xf0c):
+    case REG(0xf30) ... REG(0xfcc):
+        goto write_ignore;
+
+    default:
+        printk("vGICD: unhandled write r%d=%"PRIregister" offset %#08x\n",
+               dabt.reg, *r, offset);
+        return 0;
+    }
+
+bad_width:
+    printk("vGICD: bad write width %d r%d=%"PRIregister" offset %#08x\n",
+           dabt.size, dabt.reg, *r, offset);
+    domain_crash_synchronous();
+    return 0;
+
+write_ignore:
+    if ( dabt.size != 2 ) goto bad_width;
+    return 1;
+}
+
+static struct mmio_handler vgic_distr_mmio_handler = {
+    .read_handler  = vgic_distr_mmio_read,
+    .write_handler = vgic_distr_mmio_write,
+};
+
+static int vgic_vcpu_init(struct vcpu *v)
+{
+    int i;
+
+    /* For SGI and PPI the target is always this CPU */
+    for ( i = 0 ; i < 8 ; i++ )
+        v->arch.vgic.private_irqs->itargets[i] =
+              (1<<(v->vcpu_id+0))
+            | (1<<(v->vcpu_id+8))
+            | (1<<(v->vcpu_id+16))
+            | (1<<(v->vcpu_id+24));
+    return 0;
+}
+
+static int vgic_domain_init(struct domain *d)
+{
+    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
+    vgic_distr_mmio_handler.size = PAGE_SIZE;
+    register_mmio_handler(d, &vgic_distr_mmio_handler);
+    return 0;
+}
+
+static struct vgic_ops ops = {
+    .vgic_vcpu_init   = vgic_vcpu_init,
+    .vgic_domain_init = vgic_domain_init,
+    .read_priority    = vgic_read_priority,
+};
+
+int vgic_v2_init(struct domain *d)
+{
+    register_vgic_ops(&ops);
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 7e258ae..f487784 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -28,29 +28,20 @@
 #include <asm/current.h>
 
 #include <asm/mmio.h>
-#include <asm/gic_v2_defs.h>
 #include <asm/gic.h>
 #include <asm/vgic.h>
 
-#define REG(n) (n/4)
 
-static struct mmio_handler vgic_distr_mmio_handler;
+static struct vgic_ops *vgic_ops;
 
-/*
- * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
- * <b>-bits-per-interrupt.
- */
-#define REG_RANK_INDEX(b, n) ((n) & ((b)-1))
-
-/*
- * Returns rank corresponding to a GICD_<FOO><n> register for
- * GICD_<FOO> with <b>-bits-per-interrupt.
- */
-static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
+void register_vgic_ops(struct vgic_ops *ops)
 {
-    int rank = REG_RANK_NR(b, n);
+   vgic_ops = ops;
+}
 
-    if ( rank == 0 )
+struct vgic_irq_rank *vgic_get_irqrank(struct vcpu *v, int rank)
+{
+    if ( rank == 0 ) /* Rank 0 is nothing but GICR registers in GICv3 */
         return v->arch.vgic.private_irqs;
     else if ( rank <= DOMAIN_NR_RANKS(v->domain) )
         return &v->domain->arch.vgic.shared_irqs[rank - 1];
@@ -61,7 +52,6 @@ static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
 int domain_vgic_init(struct domain *d)
 {
     int i;
-
     d->arch.vgic.ctlr = 0;
 
     /* Currently nr_lines in vgic and gic doesn't have the same meanings
@@ -72,21 +62,34 @@ int domain_vgic_init(struct domain *d)
     else
         d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
 
+    if ( gic_hw_version() == GIC_V2 )
+        vgic_v2_init(d);
+    else
+        panic("No VGIC found\n");
+
     d->arch.vgic.shared_irqs =
         xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d));
+    if ( d->arch.vgic.shared_irqs == NULL )
+        return -ENOMEM;
+
+    for ( i = 0; i < DOMAIN_NR_RANKS(d); i++ )
+        spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
+
+    vgic_ops->vgic_domain_init(d);
+
     d->arch.vgic.pending_irqs =
         xzalloc_array(struct pending_irq, d->arch.vgic.nr_lines);
-    for (i=0; i<d->arch.vgic.nr_lines; i++)
+    if ( d->arch.vgic.pending_irqs == NULL )
+    {
+        xfree(d->arch.vgic.shared_irqs);
+        return -ENOMEM;
+    }
+
+    for ( i = 0; i < d->arch.vgic.nr_lines; i++)
     {
         INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].inflight);
         INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].lr_queue);
     }
-    for (i=0; i<DOMAIN_NR_RANKS(d); i++)
-        spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
-
-    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
-    vgic_distr_mmio_handler.size = PAGE_SIZE;
-    register_mmio_handler(d, &vgic_distr_mmio_handler);
     return 0;
 }
 
@@ -105,9 +108,13 @@ int vcpu_vgic_init(struct vcpu *v)
       return -ENOMEM;
 
     memset(v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
-
     spin_lock_init(&v->arch.vgic.private_irqs->lock);
 
+    if ( vgic_ops )
+       vgic_ops->vgic_vcpu_init(v);
+    else
+       panic("No VGIC ops found\n");
+
     memset(&v->arch.vgic.pending_irqs, 0, sizeof(v->arch.vgic.pending_irqs));
     for (i = 0; i < 32; i++)
     {
@@ -115,13 +122,6 @@ int vcpu_vgic_init(struct vcpu *v)
         INIT_LIST_HEAD(&v->arch.vgic.pending_irqs[i].lr_queue);
     }
 
-    /* For SGI and PPI the target is always this CPU */
-    for ( i = 0 ; i < 8 ; i++ )
-        v->arch.vgic.private_irqs->itargets[i] =
-              (1<<(v->vcpu_id+0))
-            | (1<<(v->vcpu_id+8))
-            | (1<<(v->vcpu_id+16))
-            | (1<<(v->vcpu_id+24));
     INIT_LIST_HEAD(&v->arch.vgic.inflight_irqs);
     INIT_LIST_HEAD(&v->arch.vgic.lr_pending);
     spin_lock_init(&v->arch.vgic.lock);
@@ -135,7 +135,7 @@ int vcpu_vgic_free(struct vcpu *v)
     return 0;
 }
 
-static uint32_t byte_read(uint32_t val, int sign, int offset)
+uint32_t byte_read(uint32_t val, int sign, int offset)
 {
     int byte = offset & 0x3;
 
@@ -147,7 +147,7 @@ static uint32_t byte_read(uint32_t val, int sign, int offset)
     return val;
 }
 
-static void byte_write(uint32_t *reg, uint32_t var, int offset)
+void byte_write(uint32_t *reg, uint32_t var, int offset)
 {
     int byte = offset & 0x3;
 
@@ -157,204 +157,7 @@ static void byte_write(uint32_t *reg, uint32_t var, int offset)
     *reg |= var;
 }
 
-static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
-{
-    struct hsr_dabt dabt = info->dabt;
-    struct cpu_user_regs *regs = guest_cpu_user_regs();
-    register_t *r = select_user_reg(regs, dabt.reg);
-    struct vgic_irq_rank *rank;
-    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
-    int gicd_reg = REG(offset);
-
-    switch ( gicd_reg )
-    {
-    case GICD_CTLR:
-        if ( dabt.size != 2 ) goto bad_width;
-        vgic_lock(v);
-        *r = v->domain->arch.vgic.ctlr;
-        vgic_unlock(v);
-        return 1;
-    case GICD_TYPER:
-        if ( dabt.size != 2 ) goto bad_width;
-        /* No secure world support for guests. */
-        vgic_lock(v);
-        *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS )
-            |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES );
-        vgic_unlock(v);
-        return 1;
-    case GICD_IIDR:
-        if ( dabt.size != 2 ) goto bad_width;
-        /*
-         * XXX Do we need a JEP106 manufacturer ID?
-         * Just use the physical h/w value for now
-         */
-        *r = 0x0000043b;
-        return 1;
-
-    /* Implementation defined -- read as zero */
-    case REG(0x020) ... REG(0x03c):
-        goto read_as_zero;
-
-    case GICD_IGROUPR ... GICD_IGROUPRN:
-        /* We do not implement security extensions for guests, read zero */
-        goto read_as_zero;
-
-    case GICD_ISENABLER ... GICD_ISENABLERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = rank->ienable;
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ICENABLER ... GICD_ICENABLERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = rank->ienable;
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ISPENDR ... GICD_ISPENDRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISPENDR);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = byte_read(rank->ipend, dabt.sign, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ICPENDR ... GICD_ICPENDRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICPENDR);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = byte_read(rank->ipend, dabt.sign, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ISACTIVER ... GICD_ISACTIVERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = rank->iactive;
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ICACTIVER ... GICD_ICACTIVERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = rank->iactive;
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ITARGETSR ... GICD_ITARGETSRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
-        if ( rank == NULL) goto read_as_zero;
-
-        vgic_lock_rank(v, rank);
-        *r = rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)];
-        if ( dabt.size == 0 )
-            *r = byte_read(*r, dabt.sign, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
-        if ( rank == NULL) goto read_as_zero;
-
-        vgic_lock_rank(v, rank);
-        *r = rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)];
-        if ( dabt.size == 0 )
-            *r = byte_read(*r, dabt.sign, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ICFGR ... GICD_ICFGRN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)];
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_NSACR ... GICD_NSACRN:
-        /* We do not implement security extensions for guests, read zero */
-        goto read_as_zero;
-
-    case GICD_SGIR:
-        if ( dabt.size != 2 ) goto bad_width;
-        /* Write only -- read unknown */
-        *r = 0xdeadbeef;
-        return 1;
-
-    case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_CPENDSGIR);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = byte_read(rank->pendsgi, dabt.sign, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_SPENDSGIR);
-        if ( rank == NULL) goto read_as_zero;
-        vgic_lock_rank(v, rank);
-        *r = byte_read(rank->pendsgi, dabt.sign, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    /* Implementation defined -- read as zero */
-    case REG(0xfd0) ... REG(0xfe4):
-        goto read_as_zero;
-
-    case GICD_ICPIDR2:
-        if ( dabt.size != 2 ) goto bad_width;
-        printk("vGICD: unhandled read from ICPIDR2\n");
-        return 0;
-
-    /* Implementation defined -- read as zero */
-    case REG(0xfec) ... REG(0xffc):
-        goto read_as_zero;
-
-    /* Reserved -- read as zero */
-    case REG(0x00c) ... REG(0x01c):
-    case REG(0x040) ... REG(0x07c):
-    case REG(0x7fc):
-    case REG(0xbfc):
-    case REG(0xf04) ... REG(0xf0c):
-    case REG(0xf30) ... REG(0xfcc):
-        goto read_as_zero;
-
-    default:
-        printk("vGICD: unhandled read r%d offset %#08x\n",
-               dabt.reg, offset);
-        return 0;
-    }
-
-bad_width:
-    printk("vGICD: bad read width %d r%d offset %#08x\n",
-           dabt.size, dabt.reg, offset);
-    domain_crash_synchronous();
-    return 0;
-
-read_as_zero:
-    if ( dabt.size != 2 ) goto bad_width;
-    *r = 0;
-    return 1;
-}
-
-static void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
+void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
 {
     const unsigned long mask = r;
     struct pending_irq *p;
@@ -372,7 +175,7 @@ static void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
     }
 }
 
-static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
+void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
 {
     const unsigned long mask = r;
     struct pending_irq *p;
@@ -400,246 +203,6 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
     }
 }
 
-static int vgic_to_sgi(struct vcpu *v, register_t sgir)
-{
-    struct domain *d = v->domain;
-    int virtual_irq;
-    int filter;
-    int vcpuid;
-    int i;
-    unsigned long vcpu_mask = 0;
-
-    ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));
-
-    filter = (sgir & GICD_SGI_TARGET_LIST_MASK);
-    virtual_irq = (sgir & GICD_SGI_INTID_MASK);
-    ASSERT( virtual_irq < 16 );
-
-    switch ( filter )
-    {
-        case GICD_SGI_TARGET_LIST:
-            vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT;
-            break;
-        case GICD_SGI_TARGET_OTHERS:
-            for ( i = 0; i < d->max_vcpus; i++ )
-            {
-                if ( i != current->vcpu_id && is_vcpu_running(d, i) )
-                    set_bit(i, &vcpu_mask);
-            }
-            break;
-        case GICD_SGI_TARGET_SELF:
-            set_bit(current->vcpu_id, &vcpu_mask);
-            break;
-        default:
-            gdprintk(XENLOG_WARNING, "vGICD: unhandled GICD_SGIR write %"PRIregister" with wrong TargetListFilter field\n",
-                     sgir);
-            return 0;
-    }
-
-    for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus )
-    {
-        if ( !is_vcpu_running(d, vcpuid) )
-        {
-            gdprintk(XENLOG_WARNING, "vGICD: GICD_SGIR write r=%"PRIregister" vcpu_mask=%lx, wrong CPUTargetList\n",
-                     sgir, vcpu_mask);
-            continue;
-        }
-        vgic_vcpu_inject_irq(d->vcpu[vcpuid], virtual_irq);
-    }
-    return 1;
-}
-
-static int vgic_distr_mmio_write(struct vcpu *v, mmio_info_t *info)
-{
-    struct hsr_dabt dabt = info->dabt;
-    struct cpu_user_regs *regs = guest_cpu_user_regs();
-    register_t *r = select_user_reg(regs, dabt.reg);
-    struct vgic_irq_rank *rank;
-    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
-    int gicd_reg = REG(offset);
-    uint32_t tr;
-
-    switch ( gicd_reg )
-    {
-    case GICD_CTLR:
-        if ( dabt.size != 2 ) goto bad_width;
-        /* Ignore all but the enable bit */
-        v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE;
-        return 1;
-
-    /* R/O -- write ignored */
-    case GICD_TYPER:
-    case GICD_IIDR:
-        goto write_ignore;
-
-    /* Implementation defined -- write ignored */
-    case REG(0x020) ... REG(0x03c):
-        goto write_ignore;
-
-    case GICD_IGROUPR ... GICD_IGROUPRN:
-        /* We do not implement security extensions for guests, write ignore */
-        goto write_ignore;
-
-    case GICD_ISENABLER ... GICD_ISENABLERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
-        if ( rank == NULL) goto write_ignore;
-        vgic_lock_rank(v, rank);
-        tr = rank->ienable;
-        rank->ienable |= *r;
-        vgic_unlock_rank(v, rank);
-        vgic_enable_irqs(v, (*r) & (~tr), gicd_reg - GICD_ISENABLER);
-        return 1;
-
-    case GICD_ICENABLER ... GICD_ICENABLERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
-        if ( rank == NULL) goto write_ignore;
-        vgic_lock_rank(v, rank);
-        tr = rank->ienable;
-        rank->ienable &= ~*r;
-        vgic_unlock_rank(v, rank);
-        vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER);
-        return 1;
-
-    case GICD_ISPENDR ... GICD_ISPENDRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDR%d\n",
-               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ISPENDR);
-        return 0;
-
-    case GICD_ICPENDR ... GICD_ICPENDRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDR%d\n",
-               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ICPENDR);
-        return 0;
-
-    case GICD_ISACTIVER ... GICD_ISACTIVERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
-        if ( rank == NULL) goto write_ignore;
-        vgic_lock_rank(v, rank);
-        rank->iactive &= ~*r;
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ICACTIVER ... GICD_ICACTIVERN:
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
-        if ( rank == NULL) goto write_ignore;
-        vgic_lock_rank(v, rank);
-        rank->iactive &= ~*r;
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ITARGETSR ... GICD_ITARGETSR + 7:
-        /* SGI/PPI target is read only */
-        goto write_ignore;
-
-    case GICD_ITARGETSR + 8 ... GICD_ITARGETSRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
-        if ( rank == NULL) goto write_ignore;
-        vgic_lock_rank(v, rank);
-        if ( dabt.size == 2 )
-            rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)] = *r;
-        else
-            byte_write(&rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)],
-                       *r, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
-        if ( rank == NULL) goto write_ignore;
-        vgic_lock_rank(v, rank);
-        if ( dabt.size == 2 )
-            rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)] = *r;
-        else
-            byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)],
-                       *r, offset);
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_ICFGR: /* SGIs */
-        goto write_ignore;
-    case GICD_ICFGR + 1: /* PPIs */
-        /* It is implementation defined if these are writeable. We chose not */
-        goto write_ignore;
-    case GICD_ICFGR + 2 ... GICD_ICFGRN: /* SPIs */
-        if ( dabt.size != 2 ) goto bad_width;
-        rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
-        vgic_lock_rank(v, rank);
-        if ( rank == NULL) goto write_ignore;
-        rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)] = *r;
-        vgic_unlock_rank(v, rank);
-        return 1;
-
-    case GICD_NSACR ... GICD_NSACRN:
-        /* We do not implement security extensions for guests, write ignore */
-        goto write_ignore;
-
-    case GICD_SGIR:
-        if ( dabt.size != 2 )
-            goto bad_width;
-        return vgic_to_sgi(v, *r);
-
-    case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDSGIR%d\n",
-               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_CPENDSGIR);
-        return 0;
-
-    case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
-        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
-        printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDSGIR%d\n",
-               dabt.size ? "word" : "byte", *r, gicd_reg - GICD_SPENDSGIR);
-        return 0;
-
-    /* Implementation defined -- write ignored */
-    case REG(0xfd0) ... REG(0xfe4):
-        goto write_ignore;
-
-    /* R/O -- write ignore */
-    case GICD_ICPIDR2:
-        goto write_ignore;
-
-    /* Implementation defined -- write ignored */
-    case REG(0xfec) ... REG(0xffc):
-        goto write_ignore;
-
-    /* Reserved -- write ignored */
-    case REG(0x00c) ... REG(0x01c):
-    case REG(0x040) ... REG(0x07c):
-    case REG(0x7fc):
-    case REG(0xbfc):
-    case REG(0xf04) ... REG(0xf0c):
-    case REG(0xf30) ... REG(0xfcc):
-        goto write_ignore;
-
-    default:
-        printk("vGICD: unhandled write r%d=%"PRIregister" offset %#08x\n",
-               dabt.reg, *r, offset);
-        return 0;
-    }
-
-bad_width:
-    printk("vGICD: bad write width %d r%d=%"PRIregister" offset %#08x\n",
-           dabt.size, dabt.reg, *r, offset);
-    domain_crash_synchronous();
-    return 0;
-
-write_ignore:
-    if ( dabt.size != 2 ) goto bad_width;
-    return 1;
-}
-
-static struct mmio_handler vgic_distr_mmio_handler = {
-    .read_handler  = vgic_distr_mmio_read,
-    .write_handler = vgic_distr_mmio_write,
-};
-
 struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
 {
     struct pending_irq *n;
@@ -666,10 +229,9 @@ void vgic_clear_pending_irqs(struct vcpu *v)
 
 void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq)
 {
-    int idx = irq >> 2, byte = irq & 0x3;
     uint8_t priority;
-    struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx);
-    struct pending_irq *iter, *n = irq_to_pending(v, irq);
+    struct pending_irq *iter;
+    struct pending_irq  *n = irq_to_pending(v, irq);
     unsigned long flags;
     bool_t running;
 
@@ -682,7 +244,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq)
         return;
     }
 
-    priority = byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, byte);
+    priority = vgic_ops->read_priority(v, irq);
 
     n->irq = irq;
     set_bit(GIC_IRQ_GUEST_PENDING, &n->status);
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index f9d6549..187846e 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -28,6 +28,12 @@ struct vgic_irq_rank {
     uint32_t itargets[8];
 };
 
+struct vgic_ops {
+    int (*vgic_vcpu_init)(struct vcpu *v);
+    int (*vgic_domain_init)(struct domain *d);
+    int (*read_priority)(struct vcpu *v, int irq);
+};
+
 /* Number of ranks of interrupt registers for a domain */
 #define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
 
@@ -75,6 +81,15 @@ extern int vcpu_vgic_init(struct vcpu *v);
 extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq);
 extern void vgic_clear_pending_irqs(struct vcpu *v);
 extern int vcpu_vgic_free(struct vcpu *v);
+extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n);
+extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n);
+
+uint32_t byte_read(uint32_t val, int sign, int offset);
+void byte_write(uint32_t *reg, uint32_t var, int offset);
+struct vgic_irq_rank *vgic_get_irqrank(struct vcpu *v, int rank);
+extern void register_vgic_ops(struct vgic_ops *ops);
+int vgic_v2_init(struct domain *d);
+
 #endif
 
 /*
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (11 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-15 20:43   ` Julien Grall
                     ` (2 more replies)
  2014-04-15 11:17 ` [PATCH v3 14/16] xen/arm: Add virtual GICv3 support vijay.kilari
                   ` (2 subsequent siblings)
  15 siblings, 3 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Add support for GIC v3 specification System register access(SRE)
is enabled to access cpu and virtual interface regiseters based
on kernel GICv3 driver.

This patch adds only basic v3 support.
Does not support Interrupt Translation support (ITS)

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/Makefile                 |    2 +-
 xen/arch/arm/gic-v3.c                 |  967 +++++++++++++++++++++++++++++++++
 xen/include/asm-arm/arm64/processor.h |   14 +
 xen/include/asm-arm/domain.h          |    6 +
 xen/include/asm-arm/gic.h             |   15 +
 xen/include/asm-arm/gic_v3_defs.h     |  198 +++++++
 6 files changed, 1201 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 20f59f4..39166aa 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -10,7 +10,7 @@ obj-y += vpsci.o
 obj-y += domctl.o
 obj-y += sysctl.o
 obj-y += domain_build.o
-obj-y += gic.o gic-v2.o
+obj-y += gic.o gic-v3.o gic-v2.o
 obj-y += io.o
 obj-y += irq.o
 obj-y += kernel.o
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
new file mode 100644
index 0000000..8625e0c
--- /dev/null
+++ b/xen/arch/arm/gic-v3.c
@@ -0,0 +1,967 @@
+/*
+ * xen/arch/arm/gic-v3.c
+ *
+ * ARM Generic Interrupt Controller support v3 version
+ * based on xen/arch/arm/gic-v2.c and kernel GICv3 driver
+ * 
+ * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
+ * Copyright (c) 2014 Cavium Inc.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/cpu.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/errno.h>
+#include <xen/serial.h>
+#include <xen/softirq.h>
+#include <xen/list.h>
+#include <xen/device_tree.h>
+#include <xen/delay.h>
+#include <asm/p2m.h>
+#include <asm/domain.h>
+#include <asm/platform.h>
+
+#include <asm/gic_v3_defs.h>
+#include <asm/gic.h>
+#include <asm/io.h>
+#include <asm/device.h>
+
+static struct gic_hw_operations gic_ops;
+
+struct rdist_region {
+    paddr_t rdist_base;
+    paddr_t rdist_base_size;
+    void __iomem *map_rdist_base;
+};
+
+/* Global state */
+static struct {
+    paddr_t dbase;            /* Address of distributor registers */
+    paddr_t dbase_size;
+    void __iomem *map_dbase;  /* Mapped address of distributor registers */
+    struct rdist_region *rdist_regions;
+    u32  rdist_stride;
+    unsigned int rdist_count; /* Number of rdist regions count */
+    unsigned int lines;       /* Number of interrupts (SPIs + PPIs + SGIs) */
+    struct dt_irq maintenance;
+}gic;
+
+/* per-cpu re-distributor base */
+static DEFINE_PER_CPU(void __iomem*, rbase);
+
+static uint8_t nr_lrs;
+static uint32_t nr_priorities;
+
+#define GICD                   (gic.map_dbase)
+#define GICD_RDIST_BASE        (this_cpu(rbase))
+#define GICD_RDIST_SGI_BASE    (GICD_RDIST_BASE + SZ_64K)
+
+static u64 gich_read_lr(int lr)
+{
+    switch ( lr )
+    {
+    case 0: /* ICH_LRn is 64 bit */
+        return READ_SYSREG(ICH_LR0_EL2);
+        break;
+    case 1:
+        return READ_SYSREG(ICH_LR1_EL2);
+        break;
+    case 2:
+        return READ_SYSREG(ICH_LR2_EL2);
+        break;
+    case 3:
+        return READ_SYSREG(ICH_LR3_EL2);
+        break;
+    case 4:
+        return READ_SYSREG(ICH_LR4_EL2);
+        break;
+    case 5:
+        return READ_SYSREG(ICH_LR5_EL2);
+        break;
+    case 6:
+        return READ_SYSREG(ICH_LR6_EL2);
+        break;
+    case 7:
+        return READ_SYSREG(ICH_LR7_EL2);
+        break;
+    case 8:
+        return READ_SYSREG(ICH_LR8_EL2);
+        break;
+    case 9:
+        return READ_SYSREG(ICH_LR9_EL2);
+        break;
+    case 10:
+        return READ_SYSREG(ICH_LR10_EL2);
+        break;
+    case 11:
+        return READ_SYSREG(ICH_LR11_EL2);
+        break;
+    case 12:
+        return READ_SYSREG(ICH_LR12_EL2);
+        break;
+    case 13:
+        return READ_SYSREG(ICH_LR13_EL2);
+        break;
+    case 14:
+        return READ_SYSREG(ICH_LR14_EL2);
+        break;
+    case 15:
+        return READ_SYSREG(ICH_LR15_EL2);
+        break;
+    default:
+        return 0;
+    }
+}
+
+static void gich_write_lr(int lr, u64 val)
+{
+    switch ( lr )
+    {
+    case 0:
+        WRITE_SYSREG(val, ICH_LR0_EL2);
+        break;
+    case 1:
+        WRITE_SYSREG(val, ICH_LR1_EL2);
+        break;
+    case 2:
+        WRITE_SYSREG(val, ICH_LR2_EL2);
+        break;
+    case 3:
+        WRITE_SYSREG(val, ICH_LR3_EL2);
+        break;
+    case 4:
+        WRITE_SYSREG(val, ICH_LR4_EL2);
+        break;
+    case 5:
+        WRITE_SYSREG(val, ICH_LR5_EL2);
+        break;
+    case 6:
+        WRITE_SYSREG(val, ICH_LR6_EL2);
+        break;
+    case 7:
+        WRITE_SYSREG(val, ICH_LR7_EL2);
+        break;
+    case 8:
+        WRITE_SYSREG(val, ICH_LR8_EL2);
+        break;
+    case 9:
+        WRITE_SYSREG(val, ICH_LR9_EL2);
+        break;
+    case 10:
+        WRITE_SYSREG(val, ICH_LR10_EL2);
+        break;
+    case 11:
+        WRITE_SYSREG(val, ICH_LR11_EL2);
+        break;
+    case 12:
+        WRITE_SYSREG(val, ICH_LR12_EL2);
+        break;
+    case 13:
+        WRITE_SYSREG(val, ICH_LR13_EL2);
+        break;
+    case 14:
+        WRITE_SYSREG(val, ICH_LR14_EL2);
+        break;
+    case 15:
+        WRITE_SYSREG(val, ICH_LR15_EL2);
+        break;
+    default:
+        return;
+    }
+}
+
+/* 
+ * System Register Enable (SRE). Enable to access CPU & Virtual
+ * interface registers as system registers in EL2
+ */
+static void gicv3_enable_sre(void)
+{
+    uint32_t val;
+
+    val = READ_SYSREG32(ICC_SRE_EL2);
+    val |= GICC_SRE_EL2_SRE | GICC_SRE_EL2_ENEL1 | GICC_SRE_EL2_DFB | GICC_SRE_EL2_DIB;
+    WRITE_SYSREG32(val, ICC_SRE_EL2);
+    isb();
+}
+
+/* Wait for completion of a distributor change */
+static void gicv3_do_wait_for_rwp(void __iomem *base)
+{
+    u32 val;
+    u32 count = 1000000;
+
+    do {
+        val = readl_relaxed(base + GICD_CTLR);
+        if ( !(val & GICD_CTLR_RWP) )
+           break;
+        cpu_relax();
+        udelay(1);
+    } while ( count-- );
+
+    if ( !count )
+        dprintk(XENLOG_WARNING, "RWP timeout\n");
+}
+
+static void gicv3_dist_wait_for_rwp(void)
+{
+    gicv3_do_wait_for_rwp(GICD);
+}
+
+static void gicv3_redist_wait_for_rwp(void)
+{
+    gicv3_do_wait_for_rwp(GICD_RDIST_BASE);
+}
+
+static void gicv3_wait_for_rwp(int irq)
+{
+    if ( irq < NR_LOCAL_IRQS )
+         gicv3_redist_wait_for_rwp();
+    else
+         gicv3_dist_wait_for_rwp();
+}
+
+static unsigned int gicv3_mask_cpu(const cpumask_t *cpumask)
+{
+    unsigned int cpu;
+    cpumask_t possible_mask;
+
+    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
+    cpu = cpumask_any(&possible_mask);
+    return cpu;
+}
+
+static void write_aprn_regs(union gic_state_data *d)
+{
+    ASSERT((nr_priorities > 4 && nr_priorities < 8));
+    /* Write APRn register based on number of priorities
+       plaform has implemented */
+    switch ( nr_priorities )
+    {
+    case 7:
+        WRITE_SYSREG32(d->v3.apr0[2], ICH_AP0R2_EL2);
+        WRITE_SYSREG32(d->v3.apr1[2], ICH_AP1R2_EL2);
+        /* Fall through */
+    case 6:
+        WRITE_SYSREG32(d->v3.apr0[1], ICH_AP0R1_EL2);
+        WRITE_SYSREG32(d->v3.apr1[1], ICH_AP1R1_EL2);
+        /* Fall through */
+    case 5:
+        WRITE_SYSREG32(d->v3.apr0[0], ICH_AP0R0_EL2);
+        WRITE_SYSREG32(d->v3.apr1[0], ICH_AP1R0_EL2);
+        break;
+    default:
+        break;
+    }
+}
+
+static void read_aprn_regs(union gic_state_data *d)
+{
+    ASSERT((nr_priorities > 4 && nr_priorities < 8));
+    /* Read APRn register based on number of priorities
+       plaform has implemented */
+    switch ( nr_priorities )
+    {
+    case 7:
+        d->v3.apr0[2] = READ_SYSREG32(ICH_AP0R2_EL2);
+        d->v3.apr1[2] = READ_SYSREG32(ICH_AP1R2_EL2);
+        /* Fall through */
+    case 6:
+        d->v3.apr0[1] = READ_SYSREG32(ICH_AP0R1_EL2);
+        d->v3.apr1[1] = READ_SYSREG32(ICH_AP1R1_EL2);
+        /* Fall through */
+    case 5:
+        d->v3.apr0[0] = READ_SYSREG32(ICH_AP0R0_EL2);
+        d->v3.apr1[0] = READ_SYSREG32(ICH_AP1R0_EL2);
+        break;
+    default:
+        break;
+    }
+}
+
+static void gicv3_save_state(struct vcpu *v)
+{
+    int i;
+
+    /* No need for spinlocks here because interrupts are disabled around
+     * this call and it only accesses struct vcpu fields that cannot be
+     * accessed simultaneously by another pCPU.
+     */
+    for ( i = 0; i < nr_lrs; i++)
+        v->arch.gic.v3.lr[i] = gich_read_lr(i);
+
+    read_aprn_regs(&v->arch.gic); 
+    v->arch.gic.v3.vmcr = READ_SYSREG32(ICH_VMCR_EL2);
+}
+
+static void gicv3_restore_state(struct vcpu *v)
+{
+    int i;
+
+    for ( i = 0; i < nr_lrs; i++)
+        gich_write_lr(i, v->arch.gic.v3.lr[i]);
+
+    write_aprn_regs(&v->arch.gic);
+
+    WRITE_SYSREG32(v->arch.gic.v3.vmcr, ICH_VMCR_EL2);
+}
+
+static void gicv3_dump_state(struct vcpu *v)
+{
+    int i;
+    if ( v == current )
+    {
+        for ( i = 0; i < nr_lrs; i++ )
+            printk("   HW_LR[%d]=%lx\n", i, gich_read_lr(i));
+    }
+    else
+    {
+        for ( i = 0; i < nr_lrs; i++ )
+            printk("   VCPU_LR[%d]=%lx\n", i, v->arch.gic.v3.lr[i]);
+    }
+}
+ 
+static void gicv3_enable_irq(struct irq_desc *irqd)
+{
+    int irq = irqd->irq;
+    uint32_t enabler;
+
+    /* Enable routing */
+    if ( irq < NR_GIC_LOCAL_IRQS )
+    {
+        enabler = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
+        enabler |= (1u << irq);
+        writel_relaxed(enabler, GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
+    }
+    else
+    {
+        enabler = readl_relaxed(GICD + GICD_ISENABLER + (irq / 32) * 4);
+        enabler |= (1u << (irq % 32));
+        writel_relaxed(enabler, GICD + GICD_ISENABLER + (irq / 32) * 4);
+    }
+    gicv3_wait_for_rwp(irq);
+}
+
+static void gicv3_disable_irq(struct irq_desc *irqd)
+{
+    int irq = irqd->irq;
+    uint32_t val;
+    /* Disable routing */
+    if ( irq < NR_GIC_LOCAL_IRQS )
+    {
+        val = 1u << irq;
+        writel_relaxed(val, GICD_RDIST_SGI_BASE + GICR_ICENABLER0);
+    } else {
+        val = 1u << (irq % 32);
+        writel_relaxed(val, GICD + GICD_ICENABLER + ((irq / 32) * 4));
+    }
+}
+
+static void gicv3_eoi_irq(struct irq_desc *irqd)
+{
+    int irq = irqd->irq;
+    /* Lower the priority */
+    WRITE_SYSREG32(irq, ICC_EOIR1_EL1);
+}
+
+static void gicv3_dir_irq(int irq)
+{
+    /* Deactivate */
+    WRITE_SYSREG32(irq, ICC_DIR_EL1);
+}
+
+static unsigned int gicv3_ack_irq(void)
+{
+    return (READ_SYSREG32(ICC_IAR1_EL1) & GICC_IA_IRQ);
+}
+
+
+static u64 gic_mpidr_to_affinity(u64 mpidr)
+{
+    u64 aff;
+    /* Make sure we don't broadcast the interrupt */
+     aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
+            MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
+            MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
+            MPIDR_AFFINITY_LEVEL(mpidr, 0)) & ~GICD_IROUTER_SPI_MODE_ANY;
+    return aff;
+}
+
+/*
+ * - needs to be called with gic.lock held
+ * - needs to be called with a valid cpu_mask, ie each cpu in the mask has
+ * already called gic_cpu_init
+ */
+static void gicv3_set_irq_property(unsigned int irq, bool_t level,
+                                   const cpumask_t *cpu_mask,
+                                   unsigned int priority)
+{
+    uint32_t cfg, edgebit;
+    u64 affinity;
+    unsigned int cpu = gicv3_mask_cpu(cpu_mask);
+
+
+    /* Set edge / level */
+    if ( irq < NR_GIC_SGI )
+        /* SGI's are always edge-triggered not need to call GICD_ICFGR0 */
+        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR0);
+    else if ( irq < NR_GIC_LOCAL_IRQS )
+        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR1);
+    else
+        cfg = readl_relaxed(GICD + GICD_ICFGR + (irq / 16) * 4);
+
+    edgebit = 2u << (2 * (irq % 16));
+    if ( level )
+        cfg &= ~edgebit;
+    else
+        cfg |= edgebit;
+
+    if ( irq < NR_GIC_SGI )
+       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR0);
+    else if ( irq < NR_GIC_LOCAL_IRQS )
+       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR1);
+    else
+       writel_relaxed(cfg, GICD + GICD_ICFGR + (irq / 16) * 4);
+
+    affinity = gic_mpidr_to_affinity(cpu_logical_map(cpu));
+    if ( irq >= NR_GIC_LOCAL_IRQS )
+        writeq_relaxed(affinity, (GICD + GICD_IROUTER + irq * 8));
+
+    /* Set priority */
+    if ( irq < NR_GIC_LOCAL_IRQS )
+    {
+        writeb_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + irq);
+    }
+    else 
+    {
+        writeb_relaxed(priority, GICD + GICD_IPRIORITYR + irq);
+    }
+}
+
+static void __init gicv3_dist_init(void)
+{
+    uint32_t type;
+    uint32_t priority;
+    u64 affinity;
+    int i;
+
+    /* Disable the distributor */
+    writel_relaxed(0, GICD + GICD_CTLR);
+
+    type = readl_relaxed(GICD + GICD_TYPER);
+    gic.lines = 32 * ((type & GICD_TYPE_LINES) + 1);
+
+    gic_ops.nr_lines = gic.lines;
+
+    printk("GIC: %d lines, (IID %8.8x).\n",
+           gic.lines, readl_relaxed(GICD + GICD_IIDR));
+
+    /* Default all global IRQs to level, active low */
+    for ( i = NR_GIC_LOCAL_IRQS; i < gic.lines; i += 16 )
+        writel_relaxed(0, GICD + GICD_ICFGR + (i / 16) * 4);
+
+    /* Default priority for global interrupts */
+    for ( i = NR_GIC_LOCAL_IRQS; i < gic.lines; i += 4 )
+    {
+        priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 |
+                    GIC_PRI_IRQ << 8 | GIC_PRI_IRQ);
+        writel_relaxed(priority, GICD + GICD_IPRIORITYR + (i / 4) * 4);
+    }
+
+    /* Disable all global interrupts */
+    for ( i = NR_GIC_LOCAL_IRQS; i < gic.lines; i += 32 )
+        writel_relaxed(0xffffffff, GICD + GICD_ICENABLER + (i / 32) * 4);
+
+    gicv3_dist_wait_for_rwp();
+
+    /* Turn on the distributor */
+    writel_relaxed(GICD_CTL_ENABLE | GICD_CTLR_ARE_NS |
+                GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, GICD + GICD_CTLR);
+ 
+    /* Route all global IRQs to this CPU */
+    affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
+    for ( i = NR_GIC_LOCAL_IRQS; i < gic.lines; i++ )
+        writeq_relaxed(affinity, GICD + GICD_IROUTER + i * 8);
+}
+
+static void gicv3_enable_redist(void)
+{
+    u32 val;
+    /* Wait for 1s */
+    u32 count = 1000000;
+
+    /* Wake up this CPU redistributor */
+    val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
+    val &= ~GICR_WAKER_ProcessorSleep;
+    writel_relaxed(val, GICD_RDIST_BASE + GICR_WAKER);
+
+    do {
+         val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
+         if ( !(val & GICR_WAKER_ChildrenAsleep) )
+           break;
+         cpu_relax();
+         udelay(1);
+    } while ( count-- );
+
+    if ( !count )
+        gdprintk(XENLOG_WARNING, "Redist enable RWP timeout\n");
+}
+
+static int __init gicv3_populate_rdist(void)
+{
+    u64 mpidr = cpu_logical_map(smp_processor_id());
+    u64 typer;
+    uint32_t aff;
+    int i;
+    uint32_t reg;
+
+    aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
+           MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
+           MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
+           MPIDR_AFFINITY_LEVEL(mpidr, 0));
+
+    for ( i = 0; i < gic.rdist_count; i++ )
+    {
+        void __iomem *ptr = gic.rdist_regions[i].map_rdist_base;
+
+        reg = readl_relaxed(ptr + GICR_PIDR2);
+        if ( (reg & GICR_PIDR2_ARCH_MASK) != GICR_PIDR2_GICV3 ) {
+            dprintk(XENLOG_WARNING, "No redistributor present @%"PRIpaddr"\n",
+                   (u64)ptr);
+            break;
+        }
+
+        do {
+            typer = readq_relaxed(ptr + GICR_TYPER);
+            if ( (typer >> 32) == aff )
+            {
+                this_cpu(rbase) = ptr;
+                printk("CPU%d: Found redistributor in region %d\n",
+                           smp_processor_id(), i);
+                return 0;
+            }
+            if ( gic.rdist_stride ) {
+                ptr += gic.rdist_stride;
+            } else {
+                ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
+                if ( typer & GICR_TYPER_VLPIS )
+                    ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
+            }
+        } while ( !(typer & GICR_TYPER_LAST) );
+    }
+
+    dprintk(XENLOG_WARNING, "CPU%d: mpidr %"PRIpaddr" has no re-distributor!\n",
+                  smp_processor_id(), mpidr);
+    return -ENODEV;
+}
+
+static void __cpuinit gicv3_cpu_init(void)
+{
+    int i;
+    uint32_t priority;
+
+    /* Register ourselves with the rest of the world */
+    if ( gicv3_populate_rdist() )
+        return;
+
+    gicv3_enable_redist();
+
+    /* Set priority on PPI and SGI interrupts */
+    priority = (GIC_PRI_IPI << 24 | GIC_PRI_IPI << 16 | GIC_PRI_IPI << 8 |
+                GIC_PRI_IPI);
+    for (i = 0; i < NR_GIC_SGI; i += 4)
+        writel_relaxed(priority,
+                GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4);
+
+    priority = (GIC_PRI_IRQ << 24 | GIC_PRI_IRQ << 16 | GIC_PRI_IRQ << 8 |
+                GIC_PRI_IRQ);
+    for (i = NR_GIC_SGI; i < NR_GIC_LOCAL_IRQS; i += 4)
+        writel_relaxed(priority,
+                GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + (i / 4) * 4);
+
+    /*
+     * Disable all PPI interrupts, ensure all SGI interrupts are
+     * enabled.
+     */
+    writel_relaxed(0xffff0000, GICD_RDIST_SGI_BASE + GICR_ICENABLER0);
+    writel_relaxed(0x0000ffff, GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
+
+    gicv3_redist_wait_for_rwp();
+
+    /* Enable system registers */
+    gicv3_enable_sre();
+
+    WRITE_SYSREG32(0, ICC_BPR1_EL1);
+    /* Set priority mask register */
+    WRITE_SYSREG32(DEFAULT_PMR_VALUE, ICC_PMR_EL1);
+
+    /* EOI drops priority too (mode 0) */
+    WRITE_SYSREG32(GICC_CTLR_EL1_EOImode_drop, ICC_CTLR_EL1);
+
+    /* Enable Group1 interrupts */
+    WRITE_SYSREG32(1, ICC_IGRPEN1_EL1);
+}
+
+static void gicv3_cpu_disable(void)
+{
+    WRITE_SYSREG32(0, ICC_CTLR_EL1);
+}
+
+static void __cpuinit gicv3_hyp_init(void)
+{
+    uint32_t vtr;
+
+    vtr = READ_SYSREG32(ICH_VTR_EL2);
+    nr_lrs  = (vtr & GICH_VTR_NRLRGS) + 1;
+    nr_priorities = ((vtr >> GICH_VTR_PRIBITS_SHIFT) &
+                    GICH_VTR_PRIBITS_MASK) + 1;
+
+    gic_ops.nr_lrs = nr_lrs;
+
+    WRITE_SYSREG32(GICH_VMCR_EOI | GICH_VMCR_VENG1, ICH_VMCR_EL2);
+    WRITE_SYSREG32(GICH_HCR_EN, ICH_HCR_EL2);
+
+    update_cpu_lr_mask();
+    vtr = READ_SYSREG32(ICH_HCR_EL2);
+}
+
+/* Set up the per-CPU parts of the GIC for a secondary CPU */
+static void gicv3_secondary_cpu_init(void)
+{
+    gicv3_cpu_init();
+    gicv3_hyp_init();
+}
+
+static void __cpuinit gicv3_hyp_disable(void)
+{
+    uint32_t vtr;
+    vtr = READ_SYSREG32(ICH_HCR_EL2);
+    vtr &= ~0x1;
+    WRITE_SYSREG32( vtr, ICH_HCR_EL2);
+}
+
+static u16 gicv3_compute_target_list(int *base_cpu, const struct cpumask *mask,
+                                   u64 cluster_id)
+{
+    int cpu = *base_cpu;
+    u64 mpidr = cpu_logical_map(cpu);
+    u16 tlist = 0;
+
+    while ( cpu < nr_cpu_ids )
+    {
+        /*
+         * If we ever get a cluster of more than 16 CPUs, just
+         * scream and skip that CPU.
+         */
+        if ( (mpidr & 0xff) >= 16 )
+        {
+            dprintk(XENLOG_WARNING, "Cluster more than 16's cpus\n");
+            goto out;
+        }
+        tlist |= 1 << (mpidr & 0xf);
+
+        cpu = cpumask_next(cpu, mask);
+        if ( cpu == nr_cpu_ids )
+        {
+            cpu--;
+            goto out;
+        }
+
+        mpidr = cpu_logical_map(cpu);
+        if ( cluster_id != (mpidr & ~0xffUL) ) {
+            cpu--;
+            goto out;
+        }
+    }
+out:
+    *base_cpu = cpu;
+    return tlist;
+}
+
+static void send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
+{
+    u64 val;
+
+    val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48        |
+           MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32        |
+           irq << 24                                        |
+           MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16        |
+           tlist);
+
+    WRITE_SYSREG(val, ICC_SGI1R_EL1);   
+}
+
+static void gicv3_send_sgi(const cpumask_t *cpumask, enum gic_sgi sgi,
+            uint8_t mode)
+{
+    int cpu = 0;
+
+    dsb();
+
+    for_each_cpu(cpu, cpumask)
+    {
+        u64 cluster_id = cpu_logical_map(cpu) & ~0xffUL;
+        u16 tlist;
+
+        tlist = gicv3_compute_target_list(&cpu, cpumask, cluster_id);
+        send_sgi(cluster_id, tlist, sgi);
+    }
+}
+
+/* Shut down the per-CPU GIC interface */
+static void gicv3_disable_interface(void)
+{
+    ASSERT(!local_irq_is_enabled());
+
+    gicv3_cpu_disable();
+    gicv3_hyp_disable();
+}
+
+static void gicv3_update_lr(int lr, struct pending_irq *p, unsigned int state)
+{
+    u64 grp = GICH_LR_GRP1;
+    u64 val = 0;
+
+    BUG_ON(lr >= nr_lrs);
+    BUG_ON(lr < 0);
+
+    val =  ((((u64)state) & 0x3) << GICH_LR_STATE_SHIFT) | grp |
+        ((((u64)p->priority) & 0xff) << GICH_LR_PRIORITY_SHIFT) |
+        (((u64)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
+
+   if ( p->desc != NULL )
+       val |= GICH_LR_HW |
+         (((u64) p->desc->irq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT);
+
+    gich_write_lr(lr, val);
+}
+
+static void gicv3_clear_lr(int lr)
+{
+    gich_write_lr(lr, 0);
+}
+
+static void gicv3_read_lr(int lr, struct gic_lr *lr_reg)
+{
+    u64 lrv;
+    lrv = gich_read_lr(lr);
+    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
+    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK; 
+    lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK;
+    lr_reg->state    = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
+    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;
+    lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;
+}
+
+static void gicv3_write_lr(int lr_reg, struct gic_lr *lr)
+{
+    u64 lrv = 0;
+    lrv = ( ((u64)(lr->pirq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT) |
+        ((u64)(lr->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT) |
+        ((u64)(lr->priority & GICH_LR_PRIORITY_MASK) << GICH_LR_PRIORITY_SHIFT) |
+        ((u64)(lr->state & GICH_LR_STATE_MASK) << GICH_LR_STATE_SHIFT) |
+        ((u64)(lr->hw_status & GICH_LR_HW_MASK)  << GICH_LR_HW_SHIFT)  |
+        ((u64)(lr->grp & GICH_LR_GRP_MASK) << GICH_LR_GRP_SHIFT) );
+    gich_write_lr(lr_reg, lrv);
+}
+
+int gicv_v3_init(struct domain *d)
+{
+    int i;
+    /*
+     * Domain 0 gets the hardware address.
+     * Guests get the virtual platform layout.
+     */
+    if ( d->domain_id == 0 )
+    {
+        d->arch.vgic.dbase = gic.dbase;
+        d->arch.vgic.dbase_size = gic.dbase_size;
+        for ( i = 0; i < gic.rdist_count; i++ )
+        {
+            d->arch.vgic.rbase[i] = gic.rdist_regions[i].rdist_base;
+            d->arch.vgic.rbase_size[i] = gic.rdist_regions[i].rdist_base_size;
+        }
+        d->arch.vgic.rdist_stride = gic.rdist_stride;
+        d->arch.vgic.rdist_count = gic.rdist_count;
+    }
+    else
+    {
+        d->arch.vgic.dbase = GUEST_GICD_BASE;
+    }
+
+    d->arch.vgic.nr_lines = 0;
+    return 0;
+}
+
+static struct dt_irq * gicv3_maintenance_irq(void)
+{
+    return &gic.maintenance;
+}
+
+static void gicv3_hcr_status(uint32_t flag, bool_t status)
+{
+    if ( status )
+      WRITE_SYSREG32((READ_SYSREG32(ICH_HCR_EL2) | flag), ICH_HCR_EL2);
+    else
+      WRITE_SYSREG32((READ_SYSREG32(ICH_HCR_EL2) & (~flag)), ICH_HCR_EL2);
+}
+
+static unsigned int gicv3_read_vmcr_priority(void)
+{
+   return ((READ_SYSREG32(ICH_VMCR_EL2) >> GICH_VMCR_PRIORITY_SHIFT) &
+            GICH_VMCR_PRIORITY_MASK);
+}
+
+static hw_irq_controller irq_ops = {
+        .enable   = gicv3_enable_irq,
+        .disable  = gicv3_disable_irq,
+        .end      = gicv3_eoi_irq,
+};
+
+static struct gic_hw_operations gic_ops = {
+    .get_maintenance_irq = gicv3_maintenance_irq,
+    .save_state          = gicv3_save_state,
+    .restore_state       = gicv3_restore_state,
+    .dump_state          = gicv3_dump_state,
+    .gicv_setup          = gicv_v3_init,
+    .gic_irq_ops         = &irq_ops,
+    .deactivate_irq      = gicv3_dir_irq,
+    .ack_irq             = gicv3_ack_irq,
+    .set_irq_property    = gicv3_set_irq_property,
+    .send_sgi            = gicv3_send_sgi,
+    .disable_interface   = gicv3_disable_interface,
+    .update_lr           = gicv3_update_lr,
+    .update_hcr_status   = gicv3_hcr_status,
+    .clear_lr            = gicv3_clear_lr,
+    .read_lr             = gicv3_read_lr,
+    .write_lr            = gicv3_write_lr,
+    .read_vmcr_priority  = gicv3_read_vmcr_priority,
+    .secondary_init      = gicv3_secondary_cpu_init,
+};
+
+/* Set up the GIC */
+static int __init gicv3_init(struct dt_device_node *node,
+                                       const void *data)
+{
+    struct rdist_region *rdist_regs;
+    int res, i;
+    uint32_t reg;
+
+    dt_device_set_used_by(node, DOMID_XEN);
+
+    res = dt_device_get_address(node, 0, &gic.dbase, &gic.dbase_size);
+    if ( res || !gic.dbase  || (gic.dbase & ~PAGE_MASK) ||
+       (gic.dbase_size & ~PAGE_MASK) )
+        panic("GIC: Cannot find a valid address for the distributor");
+
+    gic.map_dbase = ioremap_nocache(gic.dbase, gic.dbase_size);
+    if ( !gic.map_dbase )
+        panic("Failed to ioremap for GIC distributor\n");
+
+    reg = readl_relaxed(GICD + GICD_PIDR2);
+    if ( (reg & GICD_PIDR2_ARCH_MASK) != GICD_PIDR2_GICV3 )
+        panic("GIC: no distributor detected, giving up\n"); 
+
+    gic_ops.hw_version = GIC_V3;
+ 
+    if ( !dt_property_read_u32(node, "#redistributor-regions",
+                &gic.rdist_count) )
+        gic.rdist_count = 1;
+
+    if ( gic.rdist_count > MAX_RDIST_COUNT )
+        panic("GIC: Number of redistributor regions is more than \
+               MAX_RDIST_COUNT (Increase MAX_RDIST_COUNT!!)\n");
+
+    rdist_regs = xzalloc_array(struct rdist_region, gic.rdist_count);
+    if ( !rdist_regs )
+        panic("GIC: no distributor detected, giving up\n");
+
+    for ( i = 0; i < gic.rdist_count; i++ ) {
+        u64 rdist_base, rdist_size;
+
+        res = dt_device_get_address(node, 1 + i, &rdist_base, &rdist_size);
+        if ( res || !rdist_base)
+            panic("No rdist base found\n");
+
+        rdist_regs[i].rdist_base = rdist_base;
+        rdist_regs[i].rdist_base_size = rdist_size;
+    }
+
+    if ( !dt_property_read_u32(node, "redistributor-stride", &gic.rdist_stride) )
+        gic.rdist_stride = 0x0;
+
+    gic.rdist_regions= rdist_regs;
+ 
+    res = dt_device_get_irq(node, 0, &gic.maintenance);
+    if ( res )
+        panic("GIC: Cannot find the maintenance IRQ");
+
+    /* Set the GIC as the primary interrupt controller */
+    dt_interrupt_controller = node;
+
+    for ( i = 0; i < gic.rdist_count; i++ ) {
+        /* map dbase & rdist regions */
+        gic.rdist_regions[i].map_rdist_base =
+                ioremap_nocache(gic.rdist_regions[i].rdist_base,
+                          gic.rdist_regions[i].rdist_base_size);
+
+        if ( !gic.rdist_regions[i].map_rdist_base )
+            panic("Failed to ioremap for GIC redistributor\n");
+    }
+
+    printk("GIC initialization:\n"
+              "        gic_dist_addr=%"PRIpaddr"\n"
+              "        gic_dist_size=%"PRIpaddr"\n"
+              "        gic_dist_mapaddr=%"PRIpaddr"\n"
+              "        gic_rdist_regions=%d\n"
+              "        gic_rdist_stride=%x\n"
+              "        gic_rdist_base=%"PRIpaddr"\n"
+              "        gic_rdist_base_size=%"PRIpaddr"\n"
+              "        gic_rdist_base_mapaddr=%"PRIpaddr"\n"
+              "        gic_maintenance_irq=%u\n",
+              gic.dbase, gic.dbase_size, (u64)gic.map_dbase, gic.rdist_count,
+              gic.rdist_stride, gic.rdist_regions[0].rdist_base,
+              gic.rdist_regions[0].rdist_base_size,
+              (u64)gic.rdist_regions[0].map_rdist_base, gic.maintenance.irq);
+
+    gicv3_dist_init();
+    gicv3_cpu_init();
+    gicv3_hyp_init();
+
+    /* Register hw ops*/
+    register_gic_ops(&gic_ops);
+    return 0;
+}
+
+static const char * const gicv3_dt_compat[] __initconst =
+{
+    "arm,gic-v3",
+    NULL
+};
+
+DT_DEVICE_START(gicv3, "GIC", DEVICE_GIC)
+        .compatible = gicv3_dt_compat,
+        .init = gicv3_init,
+DT_DEVICE_END
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/arm64/processor.h b/xen/include/asm-arm/arm64/processor.h
index 5bf0867..3ecdc70 100644
--- a/xen/include/asm-arm/arm64/processor.h
+++ b/xen/include/asm-arm/arm64/processor.h
@@ -3,6 +3,20 @@
 
 #ifndef __ASSEMBLY__
 
+/*
+ * Macros to extract affinity level. picked from kernel
+ */
+
+#define MPIDR_LEVEL_BITS_SHIFT  3
+#define MPIDR_LEVEL_BITS        (1 << MPIDR_LEVEL_BITS_SHIFT)
+#define MPIDR_LEVEL_MASK        ((1 << MPIDR_LEVEL_BITS) - 1)
+
+#define MPIDR_LEVEL_SHIFT(level) \
+         (((1 << level) >> 1) << MPIDR_LEVEL_BITS_SHIFT)
+
+#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
+         ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK)
+
 /* Anonymous union includes both 32- and 64-bit names (e.g., r0/x0). */
 
 #define __DECL_REG(n64, n32) union {            \
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index ccd9640..c27085b 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -151,6 +151,12 @@ struct arch_domain
         /* Base address for guest GIC */
         paddr_t dbase; /* Distributor base address */
         paddr_t cbase; /* CPU base address */
+        /* GIC V3 addressing */
+        paddr_t dbase_size; /* Distributor base size */
+        paddr_t rbase[MAX_RDIST_COUNT];      /* Re-Distributor base address */
+        paddr_t rbase_size[MAX_RDIST_COUNT]; /* Re-Distributor size */
+        uint32_t rdist_stride;               /* Re-Distributor stride */
+        int rdist_count;                     /* No. of Re-Distributors */
     } vgic;
 
     struct vuart {
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 7489684..3c37120 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -18,6 +18,12 @@
 #ifndef __ASM_ARM_GIC_H__
 #define __ASM_ARM_GIC_H__
 
+#define SZ_64K  0x00010000
+
+#define NR_GIC_LOCAL_IRQS  NR_LOCAL_IRQS
+#define NR_GIC_SGI         16
+#define MAX_RDIST_COUNT    4
+
 /*
  * The minimum GICC_BPR is required to be in the range 0-3. We set
  * GICC_BPR to 0 but we must expect that it might be 3. This means we
@@ -62,6 +68,13 @@
 #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
                         DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")
 
+struct gic_v3 {
+    uint32_t hcr, vmcr;
+    uint32_t apr0[4];
+    uint32_t apr1[4];
+    uint64_t lr[16];
+};
+
 struct gic_v2 {
     uint32_t hcr, vmcr;
     uint32_t apr;
@@ -70,6 +83,7 @@ struct gic_v2 {
 
 union gic_state_data {
     struct gic_v2 v2;
+    struct gic_v3 v3;
 };
 
 /*
@@ -146,6 +160,7 @@ void gic_clear_lrs(struct vcpu *v);
 
 enum gic_version {
     GIC_V2 = 2,
+    GIC_V3 = 3,
 };
 
 struct gic_hw_operations {
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
new file mode 100644
index 0000000..578832b
--- /dev/null
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -0,0 +1,198 @@
+/*
+ * ARM Generic Interrupt Controller v3 definitions
+ *
+ * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
+ * Copyright (c) 2014 Cavium Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARM_GIC_V3_DEFS_H__
+#define __ASM_ARM_GIC_V3_DEFS_H__
+
+#define GICD_CTLR       (0x000)
+#define GICD_TYPER      (0x004)
+#define GICD_IIDR       (0x008)
+#define GICD_STATUSR    (0x010)
+#define GICD_SETSPI_NSR (0x040)
+#define GICD_CLRSPI_NSR (0x048)
+#define GICD_SETSPI_SR  (0x050)
+#define GICD_CLRSPI_SR  (0x058)
+#define GICD_IGROUPR    (0x080)
+#define GICD_IGROUPRN   (0x0FC)
+#define GICD_ISENABLER  (0x100)
+#define GICD_ISENABLERN (0x17C)
+#define GICD_ICENABLER  (0x180)
+#define GICD_ICENABLERN (0x1fC)
+#define GICD_ISPENDR    (0x200)
+#define GICD_ISPENDRN   (0x27C)
+#define GICD_ICPENDR    (0x280)
+#define GICD_ICPENDRN   (0x2FC)
+#define GICD_ISACTIVER  (0x300)
+#define GICD_ISACTIVERN (0x37C)
+#define GICD_ICACTIVER  (0x380)
+#define GICD_ICACTIVERN (0x3FC)
+#define GICD_IPRIORITYR (0x400)
+#define GICD_IPRIORITYRN (0x7F8)
+#define GICD_ICFGR      (0xC00)
+#define GICD_ICFGRN     (0xCFC)
+#define GICD_NSACR      (0xE00)
+#define GICD_NSACRN     (0xEFC)
+#define GICD_SGIR       (0xF00)
+#define GICD_CPENDSGIR  (0xF10)
+#define GICD_CPENDSGIRN (0xF1C)
+#define GICD_SPENDSGIR  (0xF20)
+#define GICD_SPENDSGIRN (0xF2C)
+#define GICD_IROUTER    (0x6000)
+#define GICD_IROUTERN   (0x7FF8)
+#define GICD_PIDR0      (0xFFE0)
+#define GICD_PIDR2      (0xFFE8)
+#define GICD_PIDR7      (0xFFDC)
+
+#define GICD_SGI_TARGET_LIST_SHIFT   (24)
+#define GICD_SGI_TARGET_LIST_MASK    (0x3UL << GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_LIST         (0UL<<GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_OTHERS       (1UL<<GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_SELF         (2UL<<GICD_SGI_TARGET_LIST_SHIFT)
+#define GICD_SGI_TARGET_SHIFT        (16)
+#define GICD_SGI_TARGET_MASK         (0xFFUL<<GICD_SGI_TARGET_SHIFT)
+#define GICD_SGI_GROUP1              (1UL<<15)
+#define GICD_SGI_INTID_MASK          (0xFUL)
+
+#define GICC_SRE_EL2_SRE             (1UL << 0)
+#define GICC_SRE_EL2_DFB             (1UL << 1)
+#define GICC_SRE_EL2_DIB             (1UL << 2)
+#define GICC_SRE_EL2_ENEL1           (1UL << 3)
+
+#define GICD_CTLR_RWP                (1UL << 31)
+#define GICD_CTLR_ARE_NS             (1U << 4)
+#define GICD_CTLR_ENABLE_G1A         (1U << 1)
+#define GICD_CTLR_ENABLE_G1          (1U << 0)
+#define GICD_IROUTER_SPI_MODE_ONE    (0UL << 31)
+#define GICD_IROUTER_SPI_MODE_ANY    (1UL << 31)
+
+#define GICH_HCR_EN                  (1 << 0)
+
+#define GICC_CTLR_EL1_EOImode_drop_dir  (0U << 1)
+#define GICC_CTLR_EL1_EOImode_drop      (1U << 1)
+
+#define GICR_WAKER_ProcessorSleep       (1U << 1)
+#define GICR_WAKER_ChildrenAsleep       (1U << 2)
+
+#define GICD_PIDR0_GICV3              (0x92)
+#define GICR_PIDR0_GICV3              (0x93)
+#define GICD_PIDR2_GICV3              (0x30)
+#define GICR_PIDR2_GICV3              GICD_PIDR2_GICV3
+#define GICD_PIDR2_ARCH_MASK          (0xf0)
+#define GICR_PIDR2_ARCH_MASK          GICD_PIDR2_ARCH_MASK
+#define GICR_SYNCR_NOT_BUSY           1
+
+#define GICR_CTLR       (0x0000)
+#define GICR_IIDR       (0x0004)
+#define GICR_TYPER      (0x0008)
+#define GICR_STATUSR    (0x0010)
+#define GICR_WAKER      (0x0014)
+#define GICR_SETLPIR    (0x0040)
+#define GICR_CLRLPIR    (0x0048)
+#define GICR_PROPBASER  (0x0070)
+#define GICR_PENDBASER  (0x0078)
+#define GICR_INVLPIR    (0x00A0)
+#define GICR_INVALLR    (0x00B0)
+#define GICR_SYNCR      (0x00C0)
+#define GICR_MOVLPIR    (0x100)
+#define GICR_MOVALLR    (0x0110)
+#define GICR_PIDR0      GICD_PIDR0
+#define GICR_PIDR2      GICD_PIDR2
+#define GICR_PIDR7      GICD_PIDR7
+
+/* GICR for SGI's & PPI's */
+
+#define GICR_IGROUPR0    (0x0080)
+#define GICR_IGRPMODR0   (0x0F80)
+#define GICR_ISENABLER0  (0x0100)
+#define GICR_ICENABLER0  (0x0180)
+#define GICR_ISPENDR0    (0x0200)
+#define GICR_ICPENDR0    (0x0280)
+#define GICR_ISACTIVER0  (0x0300)
+#define GICR_ICACTIVER0  (0x0380)
+#define GICR_IPRIORITYR0 (0x0400)
+#define GICR_IPRIORITYR7 (0x041C)
+#define GICR_ICFGR0      (0x0C00)
+#define GICR_ICFGR1      (0x0C04)
+#define GICR_NSACR       (0x0E00)
+
+#define GICR_TYPER_PLPIS                (1U << 0)
+#define GICR_TYPER_VLPIS                (1U << 1)
+#define GICR_TYPER_LAST                 (1U << 4)
+
+/* Register bits */
+#define GICD_CTL_ENABLE 0x1
+
+#define GICD_TYPE_LINES 0x01f
+#define GICD_TYPE_CPUS  0x0e0
+#define GICD_TYPE_SEC   0x400
+
+#define GICC_CTL_ENABLE 0x1
+#define GICC_CTL_EOI    (0x1 << 9)
+
+#define GICC_IA_IRQ       0x03ff
+#define GICC_IA_CPU_MASK  0x1c00
+#define GICC_IA_CPU_SHIFT 10
+
+#define DEFAULT_PMR_VALUE 0xff
+
+#define GICH_HCR_TC       (1 << 10)
+
+#define GICH_MISR_EOI     (1 << 0)
+#define GICH_MISR_U       (1 << 1)
+#define GICH_MISR_LRENP   (1 << 2)
+#define GICH_MISR_NP      (1 << 3)
+#define GICH_MISR_VGRP0E  (1 << 4)
+#define GICH_MISR_VGRP0D  (1 << 5)
+#define GICH_MISR_VGRP1E  (1 << 6)
+#define GICH_MISR_VGRP1D  (1 << 7)
+
+#define GICH_VMCR_EOI     (1 << 9)
+#define GICH_VMCR_VENG1    (1 << 1)
+
+#define GICH_LR_VIRTUAL_MASK    0xffff
+#define GICH_LR_VIRTUAL_SHIFT   0
+#define GICH_LR_PHYSICAL_MASK   0x3ff
+#define GICH_LR_PHYSICAL_SHIFT  32
+#define GICH_LR_STATE_MASK      0x3
+#define GICH_LR_STATE_SHIFT     62
+#define GICH_LR_PRIORITY_MASK   0xff
+#define GICH_LR_PRIORITY_SHIFT  48
+#define GICH_LR_HW_MASK         0x1
+#define GICH_LR_HW_SHIFT        61
+#define GICH_LR_GRP_MASK        0x1
+#define GICH_LR_GRP_SHIFT       60
+#define GICH_LR_MAINTENANCE_IRQ (1UL<<41)
+#define GICH_LR_GRP1            (1UL<<60)
+#define GICH_LR_HW              (1UL<<61)
+
+#define GICH_VTR_NRLRGS         0x3f
+#define GICH_VTR_PRIBITS_MASK   0x7
+#define GICH_VTR_PRIBITS_SHIFT  29
+
+#define GICH_VMCR_PRIORITY_MASK   0xff
+#define GICH_VMCR_PRIORITY_SHIFT  24
+
+#endif /* __ASM_ARM_GIC_V3_DEFS_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 14/16] xen/arm: Add virtual GICv3 support
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (12 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 13/16] xen/arm: Add support for GIC v3 vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-17  9:27   ` Julien Grall
  2014-04-24 10:30   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information vijay.kilari
  2014-04-15 11:17 ` [PATCH v3 16/16] xen/arm: add SGI handling for GICv3 vijay.kilari
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Add virtual GICv3 driver support

This patch adds only basic v3 support.
Does not support Interrupt Translation support (ITS)

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/Makefile             |    2 +-
 xen/arch/arm/vgic-v3.c            |  835 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic.c               |    4 +-
 xen/include/asm-arm/gic_v3_defs.h |    2 +
 xen/include/asm-arm/vgic.h        |    9 +-
 5 files changed, 849 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 39166aa..d269191 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -26,7 +26,7 @@ obj-y += smpboot.o
 obj-y += smp.o
 obj-y += shutdown.o
 obj-y += traps.o
-obj-y += vgic.o vgic-v2.o
+obj-y += vgic.o vgic-v3.o vgic-v2.o
 obj-y += vtimer.o
 obj-y += vuart.o
 obj-y += hvm.o
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
new file mode 100644
index 0000000..e3d773a
--- /dev/null
+++ b/xen/arch/arm/vgic-v3.c
@@ -0,0 +1,835 @@
+/*
+ * xen/arch/arm/vgic-v3.c
+ *
+ * ARM Virtual Generic Interrupt Controller v3 support
+ * based on xen/arch/arm/vgic.c
+ *
+ * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
+ * Copyright (c) 2014 Cavium Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/bitops.h>
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/softirq.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+
+#include <asm/current.h>
+#include <asm/device.h>
+
+#include <asm/mmio.h>
+#include <asm/gic_v3_defs.h>
+#include <asm/gic.h>
+#include <asm/vgic.h>
+
+#define REG(n) (n)
+
+/*
+ * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
+ * <b>-bits-per-interrupt.
+ */
+/* Shift n >> 2 to make it byte register diff */
+#define REG_RANK_INDEX(b, n) (((n) >> 2) & ((b)-1))
+
+/*
+ * Returns rank corresponding to a GICD_<FOO><n> register for
+ * GICD_<FOO> with <b>-bits-per-interrupt.
+ */
+static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
+{
+    int rank;
+
+    /* divide by 4 to make it byte size register difference
+      as n is difference of 4 byte size register */
+    n = n >> 2;
+    rank  = REG_RANK_NR(b, n);
+
+    return vgic_get_irqrank(v, rank);
+}
+
+static int vgic_read_priority(struct vcpu *v, int irq)
+{
+   struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, irq);
+   return byte_read(rank->ipriority[REG_RANK_INDEX(8, irq)], 0, irq & 0x3);
+}
+
+static int __vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info,
+           uint32_t offset)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    int gicr_reg = REG(offset);
+    u64 mpidr;
+    u64 aff;
+
+    switch ( gicr_reg )
+    {
+    case GICR_CTLR:
+        /* We have implemented LPI's, read zero */
+        goto read_as_zero;
+    case GICR_IIDR:
+        *r = GICR_IIDR_VAL;
+        return 1;
+    case GICR_TYPER:
+        mpidr = cpu_logical_map(smp_processor_id());
+        aff  = mpidr & ((1 << 24) - 1);
+        aff |= (mpidr >> 8) & (0xffUL << 24);
+        aff = aff << 32;
+        aff = (aff | ((u64)smp_processor_id() << 8));
+        aff = (aff | (0x9UL << 0));
+        *r = aff;
+        return 1;
+    case GICR_STATUSR:
+        /* Not implemented */
+        goto read_as_zero;
+    case GICR_WAKER:
+        /* Not implemented */
+        goto read_as_zero;
+    case GICR_SETLPIR:
+    case GICR_CLRLPIR:
+        /* WO return fail */
+        return 0;
+    case GICR_PROPBASER:
+        /* LPI's not implemented */
+        goto read_as_zero;
+    case GICR_PENDBASER:
+        /* LPI's not implemented */
+        goto read_as_zero;
+    case GICR_INVLPIR:
+    case GICR_INVALLR:
+        /* WO return fail*/
+        return 0;
+    case GICR_SYNCR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* RO */
+        /* Return as not busy */
+        *r = GICR_SYNCR_NOT_BUSY;
+        return 1;
+    case GICR_MOVLPIR:
+    case GICR_MOVALLR:
+        /* WO */
+        return 0;
+    case GICR_PIDR7... GICR_PIDR0:
+        *r = GICR_PIDR0_GICV3;
+         return 1;
+    default:
+        printk("vGICR: read r%d offset %#08x\n not found", dabt.reg, offset);
+        return 0;
+    }
+bad_width:
+    printk("vGICD: bad read width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, offset);
+    domain_crash_synchronous();
+    return 0;
+
+read_as_zero:
+    if ( dabt.size != 2 ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int __vgic_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info,
+          uint32_t offset)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    int gicr_reg = REG(offset);
+
+    switch ( gicr_reg )
+    {
+    case GICR_CTLR:
+        /* We do not implement LPI's, read zero */
+        goto write_ignore;
+    case GICR_IIDR:
+    case GICR_TYPER:
+        /* RO */
+        goto write_ignore;
+    case GICR_STATUSR:
+        /* Not implemented */
+        goto write_ignore;
+    case GICR_WAKER:
+        /* Not implemented */
+        goto write_ignore;
+    case GICR_SETLPIR:
+        /* Not implemented */
+        goto write_ignore;
+    case GICR_CLRLPIR:
+        /* Not implemented */
+        goto write_ignore;
+    case GICR_PROPBASER:
+        /* LPI is not implemented */
+        goto write_ignore;
+    case GICR_PENDBASER:
+        /* LPI is not implemented */
+        goto write_ignore;
+    case GICR_INVLPIR:
+        return 1;
+    case GICR_INVALLR:
+        return 1;
+    case GICR_SYNCR:
+        /* RO */
+        goto write_ignore;
+    case GICR_MOVLPIR:
+        return 1;
+    case GICR_MOVALLR:
+        return 1;
+    case GICR_PIDR7... GICR_PIDR0:
+        /* RO */
+        goto write_ignore;
+    default:
+        printk("vGICR: write r%d offset %#08x\n not found", dabt.reg, offset);
+        return 0;
+    }
+bad_width:
+    printk("vGICR: bad write width %d r%d=%"PRIregister" offset %#08x\n",
+           dabt.size, dabt.reg, *r, offset);
+    domain_crash_synchronous();
+    return 0;
+
+write_ignore:
+    if ( dabt.size != 2 ) goto bad_width;
+    return 1;
+}
+
+static int vgic_rdistr_sgi_mmio_read(struct vcpu *v, mmio_info_t *info,
+           uint32_t offset)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    struct vgic_irq_rank *rank;
+    int gicr_reg = REG(offset);
+
+    switch ( gicr_reg )
+    {
+    case GICR_IGROUPR0:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+    case GICR_IGRPMODR0:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+    case GICR_ISENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISENABLER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICENABLER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ISPENDR0:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISPENDR0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->ipend, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICPENDR0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICPENDR0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->ipend, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ISACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISACTIVER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICACTIVER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_IPRIORITYR0...GICR_IPRIORITYR7:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicr_reg - GICR_IPRIORITYR0);
+        if ( rank == NULL ) goto read_as_zero;
+
+        vgic_lock_rank(v, rank);
+        *r = rank->ipriority[REG_RANK_INDEX(8, gicr_reg - GICR_IPRIORITYR0)];
+        if ( dabt.size == 0 )
+            *r = byte_read(*r, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICFGR0... GICR_ICFGR1:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 2, gicr_reg - GICR_ICFGR0);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->icfg[REG_RANK_INDEX(2, gicr_reg - GICR_ICFGR0)];
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_NSACR:
+        if ( dabt.size != 2 ) goto bad_width;
+        return 1;
+    default:
+        printk("vGICR: read r%d offset %#08x\n not found", dabt.reg, offset);
+        return 0;
+    }
+bad_width:
+    printk("vGICR: bad read width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, offset);
+    domain_crash_synchronous();
+    return 0;
+
+read_as_zero:
+    if ( dabt.size != 2 ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int vgic_rdistr_sgi_mmio_write(struct vcpu *v, mmio_info_t *info,
+           uint32_t offset)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    struct vgic_irq_rank *rank;
+    int gicr_reg = REG(offset);
+    uint32_t tr;
+
+    switch ( gicr_reg )
+    {
+    case GICR_IGROUPR0:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    case GICR_IGRPMODR0:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    case GICR_ISENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISENABLER0);
+        if ( rank == NULL ) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        tr = rank->ienable;
+        rank->ienable |= *r;
+        vgic_unlock_rank(v, rank);
+        vgic_enable_irqs(v, (*r) & (~tr), (gicr_reg - GICR_ISENABLER0) >> 2);
+        return 1;
+    case GICR_ICENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICENABLER0);
+        if ( rank == NULL ) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->ienable &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ISPENDR0:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case GICR_ICPENDR0:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case GICR_ISACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISACTIVER0);
+        if ( rank == NULL ) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICACTIVER0);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_IPRIORITYR0...GICR_IPRIORITYR7:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicr_reg - GICR_IPRIORITYR0);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        if ( dabt.size == 2 )
+            rank->ipriority[REG_RANK_INDEX(8, gicr_reg - GICR_IPRIORITYR0)] = *r;
+        else
+            byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicr_reg - GICR_IPRIORITYR0)],
+                       *r, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICFGR0:
+        /* RO */
+    case GICR_ICFGR1:
+        goto write_ignore;
+    case GICR_NSACR:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    default:
+        printk("vGICR SGI: write r%d offset %#08x\n not found",
+               dabt.reg, offset);
+        return 0;
+    }
+bad_width:
+    printk("vGICR SGI: bad write width %d r%d=%"PRIregister" offset %#08x\n",
+           dabt.size, dabt.reg, *r, offset);
+    domain_crash_synchronous();
+    return 0;
+
+write_ignore:
+    if ( dabt.size != 2 ) goto bad_width;
+    return 1;
+}
+
+static int vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+
+    if ( !v->domain->arch.vgic.rdist_stride )
+        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
+    else
+        offset = info->gpa & 0x1FFFF;
+
+    if ( offset < SZ_64K )
+       return __vgic_rdistr_mmio_read(v, info, offset);
+    else if ( (offset - SZ_64K) < SZ_64K )
+       return vgic_rdistr_sgi_mmio_read(v, info, (offset - SZ_64K));
+    else
+       dprintk(XENLOG_WARNING, "vGICR: wrong gpa read address %"PRIpaddr"\n",
+               info->gpa);
+    return 0;
+}
+
+static int vgic_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+
+    if ( !v->domain->arch.vgic.rdist_stride )
+        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
+    else
+        offset = info->gpa & 0x1FFFF;
+
+    if ( offset < SZ_64K )
+       return __vgic_rdistr_mmio_write(v, info, offset);
+    else if ( (offset - SZ_64K) < SZ_64K )
+       return vgic_rdistr_sgi_mmio_write(v, info, (offset - SZ_64K));
+    else
+       dprintk(XENLOG_WARNING, "vGICR: wrong gpa write %"PRIpaddr"\n",
+               info->gpa);
+    return 0;
+}
+
+static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    struct vgic_irq_rank *rank;
+    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
+    int gicd_reg = REG(offset);
+
+    switch ( gicd_reg )
+    {
+    case GICD_CTLR:
+        if ( dabt.size != 2 ) goto bad_width;
+        vgic_lock(v);
+        *r = v->domain->arch.vgic.ctlr;
+        vgic_unlock(v);
+        return 1;
+    case GICD_TYPER:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* No secure world support for guests. */
+        vgic_lock(v);
+        *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS )
+            |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES );
+        vgic_unlock(v);
+        return 1;
+    case GICD_STATUSR:
+        /* Not implemented */
+        goto read_as_zero;
+    case GICD_IIDR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /*
+         * XXX Do we need a JEP106 manufacturer ID?
+         * Just use the physical h/w value for now
+         */
+        *r = GICD_IIDR_VAL;
+        return 1;
+    /* Implementation defined -- read as zero */
+    case REG(0x020) ... REG(0x03c):
+        goto read_as_zero;
+    case GICD_IGROUPR ... GICD_IGROUPRN:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+    case GICD_ISENABLER ... GICD_ISENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ICENABLER ... GICD_ICENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ISPENDR ... GICD_ISPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISPENDR);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->ipend, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ICPENDR ... GICD_ICPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICPENDR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->ipend, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ISACTIVER ... GICD_ISACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ICACTIVER ... GICD_ICACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_IROUTER ... GICD_IROUTERN:
+        rank = vgic_irq_rank(v, 64, gicd_reg - GICD_IROUTERN);
+        if ( rank == NULL) goto read_as_zero;
+
+        vgic_lock_rank(v, rank);
+        /* IROUTER is 64 bit so, to make it byte size right shift by 3.
+           Here once. macro REG_RANK_INDEX will do it twice */
+        *r = rank->irouter[REG_RANK_INDEX(64, (gicd_reg - GICD_IROUTER) >> 1)];
+        if ( dabt.size == 0 )
+            *r = byte_read(*r, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
+        if ( rank == NULL) goto read_as_zero;
+
+        vgic_lock_rank(v, rank);
+        *r = rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)];
+        if ( dabt.size == 0 )
+            *r = byte_read(*r, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ICFGR ... GICD_ICFGRN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)];
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_NSACR ... GICD_NSACRN:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+    case GICD_SGIR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* Write only -- read unknown */
+        *r = 0xdeadbeef;
+        return 1;
+    case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_CPENDSGIR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->pendsgi, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_SPENDSGIR);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = byte_read(rank->pendsgi, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_PIDR7... GICD_PIDR0:
+        /* GICv3 identification value */
+        *r = GICD_PIDR0_GICV3;
+        return 1;
+    case REG(0x00c):
+    case REG(0x044):
+    case REG(0x04c):
+    case REG(0x05c) ... REG(0x07c):
+    case REG(0xf30) ... REG(0x5fcc):
+    case REG(0x8000) ... REG(0xbfcc):
+    case REG(0xc000) ... REG(0xffcc):
+        printk("vGICD: read unknown 0x00c .. 0xfcc r%d offset %#08x\n",
+               dabt.reg, offset);
+        goto read_as_zero;
+
+    default:
+        printk("vGICD: unhandled read r%d offset %#08x\n",
+               dabt.reg, offset);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_ERR, "vGICD: bad read width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, offset);
+    domain_crash_synchronous();
+    return 0;
+
+read_as_zero:
+    printk("vGICD: read as zero %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, offset);
+    if ( dabt.size != 2 ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int vgic_distr_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    struct vgic_irq_rank *rank;
+    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
+    int gicd_reg = REG(offset);
+    uint32_t tr;
+
+    switch ( gicd_reg )
+    {
+    case GICD_CTLR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* Ignore all but the enable bit */
+        v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE;
+        return 1;
+
+    /* R/O -- write ignored */
+    case GICD_TYPER:
+    case GICD_IIDR:
+        goto write_ignore;
+    case GICD_STATUSR:
+        goto write_ignore;
+    case GICD_SETSPI_NSR:
+        goto write_ignore;
+    case GICD_CLRSPI_NSR:
+        goto write_ignore;
+    case GICD_SETSPI_SR:
+        goto write_ignore;
+    case GICD_CLRSPI_SR:
+        goto write_ignore;
+    /* Implementation defined -- write ignored */
+    case REG(0x020) ... REG(0x03c):
+        printk("vGICD: write unknown 0x020 - 0x03c r%d offset %#08x\n",
+               dabt.reg, offset);
+        goto write_ignore;
+    case GICD_IGROUPR ... GICD_IGROUPRN:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    case GICD_ISENABLER ... GICD_ISENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        tr = rank->ienable;
+        rank->ienable |= *r;
+        vgic_unlock_rank(v, rank);
+        vgic_enable_irqs(v, (*r) & (~tr), (gicd_reg - GICD_ISENABLER) >> 2);
+        return 1;
+    case GICD_ICENABLER ... GICD_ICENABLERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        tr = rank->ienable;
+        rank->ienable &= ~*r;
+        vgic_unlock_rank(v, rank);
+        vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER);
+        return 1;
+    case GICD_ISPENDR ... GICD_ISPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case GICD_ICPENDR ... GICD_ICPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case GICD_ISACTIVER ... GICD_ISACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ICACTIVER ... GICD_ICACTIVERN:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_IROUTER ... GICD_IROUTER + 8*7:
+        /* SGI/PPI target is read only */
+        goto write_ignore;
+    case GICD_IROUTER + 8*8 ... GICD_IROUTERN:
+        rank = vgic_irq_rank(v, 64, gicd_reg - GICD_IROUTER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->irouter[REG_RANK_INDEX(64, (gicd_reg - GICD_IROUTER)>>1)] = *r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        if ( dabt.size == 2 )
+            rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)] = *r;
+        else
+            byte_write(&rank->ipriority[REG_RANK_INDEX(8,
+                       gicd_reg - GICD_IPRIORITYR)], *r, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_ICFGR: /* SGIs */
+        goto write_ignore;
+    case GICD_ICFGR + 4: /* PPIs */
+        /* It is implementation defined if these are writeable. We chose not */
+        goto write_ignore;
+    case GICD_ICFGR + 8 ... GICD_ICFGRN: /* SPIs */
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
+        vgic_lock_rank(v, rank);
+        if ( rank == NULL) goto write_ignore;
+        rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)] = *r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICD_NSACR ... GICD_NSACRN:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    case GICD_SGIR:
+        /* it is accessed as system register */
+        goto write_ignore;
+    case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case REG(0x00c):
+    case REG(0x044):
+    case REG(0x04c):
+    case REG(0x05c) ... REG(0x07c):
+    case REG(0xf30) ... REG(0x5fcc):
+    case REG(0x8000) ... REG(0xbfcc):
+    case REG(0xc000) ... REG(0xffcc):
+        printk("vGICD: write unknown 0x00c 0xfcc  r%d offset %#08x\n", dabt.reg, offset);
+        goto write_ignore;
+    default:
+        printk("vGICD: unhandled write r%d=%"PRIregister" offset %#08x\n",
+               dabt.reg, *r, offset);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_ERR, "vGICD: bad write width %d r%d=%"PRIregister" \
+            offset %#08x\n", dabt.size, dabt.reg, *r, offset);
+    domain_crash_synchronous();
+    return 0;
+
+write_ignore:
+    if ( dabt.size != 2 ) goto bad_width;
+    return 1;
+}
+
+static struct mmio_handler vgic_rdistr_mmio_handler = {
+    .read_handler  = vgic_rdistr_mmio_read,
+    .write_handler = vgic_rdistr_mmio_write,
+};
+
+static struct mmio_handler vgic_distr_mmio_handler = {
+    .read_handler  = vgic_distr_mmio_read,
+    .write_handler = vgic_distr_mmio_write,
+};
+
+static int vgic_vcpu_init(struct vcpu *v)
+{
+    int i;
+    u64 affinity;
+
+    /* For SGI and PPI the target is always this CPU */
+    affinity = cpu_logical_map(v->vcpu_id);
+    for ( i = 0 ; i < 32 ; i++ )
+        v->arch.vgic.private_irqs->irouter[i] = affinity;
+    return 0;
+}
+
+static int vgic_domain_init(struct domain *d)
+{
+    int i;
+
+    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
+    vgic_distr_mmio_handler.size = d->arch.vgic.dbase_size;
+    register_mmio_handler(d, &vgic_distr_mmio_handler);
+
+    for ( i = 0; i < d->arch.vgic.rdist_count; i++ )
+    {
+        vgic_rdistr_mmio_handler.addr = d->arch.vgic.rbase[i];
+        vgic_rdistr_mmio_handler.size = d->arch.vgic.rbase_size[i];
+        register_mmio_handler(d, &vgic_rdistr_mmio_handler);
+    }
+    return 0;
+}
+
+static struct vgic_ops ops = {
+    .vgic_vcpu_init   = vgic_vcpu_init,
+    .vgic_domain_init = vgic_domain_init,
+    .read_priority = vgic_read_priority,
+};
+
+int vgic_v3_init(struct domain *d)
+{
+    register_vgic_ops(&ops);
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index f487784..0ad5e51 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -62,7 +62,9 @@ int domain_vgic_init(struct domain *d)
     else
         d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
 
-    if ( gic_hw_version() == GIC_V2 )
+    if ( gic_hw_version() == GIC_V3 )
+        vgic_v3_init(d);
+    else if ( gic_hw_version() == GIC_V2 )
         vgic_v2_init(d);
     else
         panic("No VGIC found\n");
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 578832b..f7f7932 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -94,6 +94,8 @@
 #define GICD_PIDR2_ARCH_MASK          (0xf0)
 #define GICR_PIDR2_ARCH_MASK          GICD_PIDR2_ARCH_MASK
 #define GICR_SYNCR_NOT_BUSY           1
+#define GICD_IIDR_VAL                 0x34c
+#define GICR_IIDR_VAL                 GICD_IIDR_VAL
 
 #define GICR_CTLR       (0x0000)
 #define GICR_IIDR       (0x0004)
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 187846e..0de74eb 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -25,7 +25,10 @@ struct vgic_irq_rank {
     uint32_t ienable, iactive, ipend, pendsgi;
     uint32_t icfg[2];
     uint32_t ipriority[8];
-    uint32_t itargets[8];
+    union {
+        uint32_t itargets[8];
+        uint64_t irouter[32];
+   };
 };
 
 struct vgic_ops {
@@ -51,6 +54,9 @@ static inline int REG_RANK_NR(int b, uint32_t n)
 {
     switch ( b )
     {
+    case 64: return n >> 6;
+    case 32: return n >> 5;
+    case 16: return n >> 4;
     case 8: return n >> 3;
     case 4: return n >> 2;
     case 2: return n >> 1;
@@ -89,6 +95,7 @@ void byte_write(uint32_t *reg, uint32_t var, int offset);
 struct vgic_irq_rank *vgic_get_irqrank(struct vcpu *v, int rank);
 extern void register_vgic_ops(struct vgic_ops *ops);
 int vgic_v2_init(struct domain *d);
+int vgic_v3_init(struct domain *d);
 
 #endif
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (13 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 14/16] xen/arm: Add virtual GICv3 support vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-18 19:57   ` Julien Grall
  2014-04-24 10:46   ` Ian Campbell
  2014-04-15 11:17 ` [PATCH v3 16/16] xen/arm: add SGI handling for GICv3 vijay.kilari
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Update GIC device tree node for DOM0 with GICv3
information. GIC hw specfic device tree information
is moved to respective GIC driver.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/domain_build.c |    9 +++------
 xen/arch/arm/gic-v2.c       |    9 +++++++++
 xen/arch/arm/gic-v3.c       |   33 +++++++++++++++++++++++++++++++++
 xen/arch/arm/gic.c          |    5 +++++
 xen/include/asm-arm/gic.h   |    4 ++++
 5 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 5ca2f15..5ef08da 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -576,13 +576,10 @@ static int make_gic_node(const struct domain *d, void *fdt,
         return -FDT_ERR_XEN(ENOMEM);
 
     tmp = new_cells;
-    DPRINT("  Set Distributor Base 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
-           d->arch.vgic.dbase, d->arch.vgic.dbase + PAGE_SIZE - 1);
-    dt_set_range(&tmp, node, d->arch.vgic.dbase, PAGE_SIZE);
 
-    DPRINT("  Set Cpu Base 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
-           d->arch.vgic.cbase, d->arch.vgic.cbase + (PAGE_SIZE * 2) - 1);
-    dt_set_range(&tmp, node, d->arch.vgic.cbase, PAGE_SIZE * 2);
+    res = gic_make_node(d, node, fdt, tmp);
+    if ( res )
+        return res;
 
     res = fdt_property(fdt, "reg", new_cells, len);
     xfree(new_cells);
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 1e62dd9..cacb9e4 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -487,6 +487,14 @@ static unsigned int gicv2_read_vmcr_priority(void)
    return (GICH[GICH_VMCR] >> GICH_VMCR_PRIORITY_SHIFT) & GICH_VMCR_PRIORITY_MASK;
 }
 
+int static gicv3_make_dt_node(const struct domain *d,
+              const struct dt_device_node *node, void *fdt, __be32 *cells)
+{
+    dt_set_range(&cells, node, d->arch.vgic.dbase, PAGE_SIZE);
+    dt_set_range(&cells, node, d->arch.vgic.cbase, PAGE_SIZE * 2);
+    return 0;
+}
+
 static hw_irq_controller irq_ops = {
     .enable              = gicv2_enable_irq,
     .disable             = gicv2_disable_irq,
@@ -512,6 +520,7 @@ static struct gic_hw_operations gic_ops = {
     .read_lr             = gicv2_read_lr,
     .write_lr            = gicv2_write_lr,
     .read_vmcr_priority  = gicv2_read_vmcr_priority,
+    .make_dt_node        = gicv3_make_dt_node,
 };
 
 static const char * const gicv2_dt_compat[] __initconst =
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 8625e0c..e27b094 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -30,6 +30,7 @@
 #include <xen/softirq.h>
 #include <xen/list.h>
 #include <xen/device_tree.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/delay.h>
 #include <asm/p2m.h>
 #include <asm/domain.h>
@@ -825,6 +826,37 @@ static unsigned int gicv3_read_vmcr_priority(void)
             GICH_VMCR_PRIORITY_MASK);
 }
 
+int static gicv3_make_dt_node(const struct domain *d,
+              const struct dt_device_node *node, void *fdt, __be32 *cells)
+{
+    uint32_t rd_stride = 0;
+    uint32_t rd_count = 0;
+    int res, i;
+
+    const struct dt_device_node *gic = dt_interrupt_controller;
+    res = dt_property_read_u32(gic, "redistributor-stride", &rd_stride);
+    if ( !res )
+        rd_stride = 0;
+
+    res = dt_property_read_u32(gic, "#redistributor-regions", &rd_count);
+    if ( !res )
+        rd_count = 1;
+
+    res = fdt_property_cell(fdt, "redistributor-stride", rd_stride);
+    if ( res )
+        return res;
+
+    res = fdt_property_cell(fdt, "#redistributor-regions", rd_count);
+    if ( res )
+        return res;
+
+    dt_set_range(&cells, node, d->arch.vgic.dbase, d->arch.vgic.dbase_size);
+
+    for ( i = 0; i < d->arch.vgic.rdist_count; i++ )
+        dt_set_range(&cells, node, d->arch.vgic.rbase[i],
+                     d->arch.vgic.rbase_size[i]);
+    return 0;
+}
 static hw_irq_controller irq_ops = {
         .enable   = gicv3_enable_irq,
         .disable  = gicv3_disable_irq,
@@ -850,6 +882,7 @@ static struct gic_hw_operations gic_ops = {
     .write_lr            = gicv3_write_lr,
     .read_vmcr_priority  = gicv3_read_vmcr_priority,
     .secondary_init      = gicv3_secondary_cpu_init,
+    .make_dt_node        = gicv3_make_dt_node,
 };
 
 /* Set up the GIC */
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 4a86c42..2632a0b 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -811,6 +811,11 @@ void __cpuinit init_maintenance_interrupt(void)
                    "irq-maintenance", NULL);
 }
 
+int gic_make_node(const struct domain *d,const struct dt_device_node *node,
+                   void *fdt, __be32 *cells)
+{
+    return gic_hw_ops->make_dt_node(d, node, fdt, cells);
+}
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 3c37120..e5dfcf8 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -211,10 +211,14 @@ struct gic_hw_operations {
     unsigned int (*read_vmcr_priority)(void);
     /* Secondary CPU init */
     void (*secondary_init)(void);
+    int (*make_dt_node)(const struct domain *d,
+              const struct dt_device_node *node, void *fdt, __be32 *cells);
 };
 
 void register_gic_ops(const struct gic_hw_operations *ops);
 extern void update_cpu_lr_mask(void);
+int gic_make_node(const struct domain *d,const struct dt_device_node *node,
+                   void *fdt, __be32 *cells);
 
 #endif /* __ASSEMBLY__ */
 #endif
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
                   ` (14 preceding siblings ...)
  2014-04-15 11:17 ` [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information vijay.kilari
@ 2014-04-15 11:17 ` vijay.kilari
  2014-04-18 20:20   ` Julien Grall
  2014-04-24 10:57   ` Ian Campbell
  15 siblings, 2 replies; 107+ messages in thread
From: vijay.kilari @ 2014-04-15 11:17 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, vijay.kilari

From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
Handle the trap and inject SGI to vcpu.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/traps.c              |    9 +++++
 xen/arch/arm/vgic-v3.c            |   79 +++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic_v3_defs.h |   14 +++++++
 xen/include/asm-arm/sysregs.h     |    2 +-
 xen/include/asm-arm/vgic.h        |    1 +
 5 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index e0184b1..dc1f202 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -40,6 +40,7 @@
 #include "decode.h"
 #include "vtimer.h"
 #include <asm/gic.h>
+#include <asm/vgic.h>
 
 /* The base of the stack must always be double-word aligned, which means
  * that both the kernel half of struct cpu_user_regs (which is pushed in
@@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
             domain_crash_synchronous();
         }
         break;
+    case HSR_SYSREG_ICC_SGI1R_EL1:
+        if ( !vgic_emulate(regs, hsr) )
+        {
+            dprintk(XENLOG_ERR,
+                    "failed emulation of 64-bit vgic sysreg access\n");
+            domain_crash_synchronous();
+        }
+        break;
     default:
         printk("%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n",
                sysreg.read ? "mrs" : "msr",
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index e3d773a..2bef977 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -774,6 +774,85 @@ write_ignore:
     return 1;
 }
 
+static int vgic_to_sgi(struct vcpu *v, register_t sgir)
+{
+    struct domain *d = v->domain;
+    int virq;
+    int irqmode;
+    int vcpuid;
+    int i;
+    unsigned long vcpu_mask = 0;
+
+    ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));
+
+    irqmode = (sgir >> ICH_SGI_IRQMODE_SHIFT) & ICH_SGI_IRQMODE_MASK;
+    virq = (sgir >> ICH_SGI_IRQ_SHIFT ) & ICH_SGI_IRQ_MASK;
+
+    ASSERT( virq < 16 );
+
+    switch ( irqmode )
+    {
+    case ICH_SGI_TARGET_LIST:
+        vcpu_mask = sgir & ICH_SGI_TARGETLIST_MASK;
+        break;
+    case ICH_SGI_TARGET_OTHERS:
+        for ( i = 0; i < d->max_vcpus; i++ )
+        {
+            if ( i != current->vcpu_id && is_vcpu_running(d, i) )
+                set_bit(i, &vcpu_mask);
+        }
+        break;
+    default:
+        gdprintk(XENLOG_WARNING, "vGICD: unhandled GICD_SGIR write %"PRIregister" with wrong mode\n",
+                 sgir);
+       return 0;
+    }
+
+    for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus )
+    {
+        if ( !is_vcpu_running(d, vcpuid) )
+        {
+            gdprintk(XENLOG_WARNING, " write r=%"PRIregister" vcpu_mask=%lx, wrong CPUTargetList\n",
+                     sgir, vcpu_mask);
+            continue;
+        }
+        vgic_vcpu_inject_irq(d->vcpu[vcpuid], virq);
+    }
+    return 1;
+}
+
+static int vgic_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
+{
+    struct vcpu *v = current;
+    struct hsr_sysreg sysreg = hsr.sysreg;
+    register_t *r = select_user_reg(regs, sysreg.reg);
+    switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
+    {
+    case HSR_SYSREG_ICC_SGI1R_EL1:
+        /* WO */
+        if ( !sysreg.read )
+            return vgic_to_sgi(v, *r);
+        else
+        {
+            gdprintk(XENLOG_WARNING, "Reading SGI1R_EL1 - WO register\n");
+            return 0;
+        }
+    default:
+        return 0;
+    }
+}
+
+int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
+{
+    switch ( hsr.ec )
+    {
+    case HSR_EC_SYSREG:
+        return vgic_emulate_sysreg(regs, hsr);
+    default:
+        return 0;
+    }
+}
+
 static struct mmio_handler vgic_rdistr_mmio_handler = {
     .read_handler  = vgic_rdistr_mmio_read,
     .write_handler = vgic_rdistr_mmio_write,
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index f7f7932..750cd5b 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -188,6 +188,20 @@
 #define GICH_VMCR_PRIORITY_MASK   0xff
 #define GICH_VMCR_PRIORITY_SHIFT  24
 
+#define ICH_SGIR_AFFINITY_3_SHIFT 48
+#define ICH_SGIR_AFFINITY_3_MASK  0xff
+#define ICH_SGIR_AFFINITY_2_SHIFT 32
+#define ICH_SGIR_AFFINITY_2_MASK  0xff
+#define ICH_SGIR_AFFINITY_1_SHIFT 16
+#define ICH_SGIR_AFFINITY_1_MASK  0xff
+#define ICH_SGI_IRQMODE_SHIFT     40
+#define ICH_SGI_IRQMODE_MASK      0x1
+#define ICH_SGI_TARGET_OTHERS     1
+#define ICH_SGI_TARGET_LIST       0
+#define ICH_SGI_IRQ_SHIFT         24
+#define ICH_SGI_IRQ_MASK          0xf
+#define ICH_SGI_TARGETLIST_MASK   0xffff
+
 #endif /* __ASM_ARM_GIC_V3_DEFS_H__ */
 
 /*
diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h
index 0cee0e9..18e5a45 100644
--- a/xen/include/asm-arm/sysregs.h
+++ b/xen/include/asm-arm/sysregs.h
@@ -56,7 +56,7 @@
 #define HSR_SYSREG_CNTP_CTL_EL0   HSR_SYSREG(3,3,c14,c2,1)
 #define HSR_SYSREG_CNTP_TVAL_EL0  HSR_SYSREG(3,3,c14,c2,0)
 
-
+#define HSR_SYSREG_ICC_SGI1R_EL1  HSR_SYSREG(3,0,c12,c11,5)
 #endif
 
 #endif
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 0de74eb..5bc3650 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -89,6 +89,7 @@ extern void vgic_clear_pending_irqs(struct vcpu *v);
 extern int vcpu_vgic_free(struct vcpu *v);
 extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n);
 extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n);
+extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr);
 
 uint32_t byte_read(uint32_t val, int sign, int offset);
 void byte_write(uint32_t *reg, uint32_t var, int offset);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder
  2014-04-15 11:17 ` [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder vijay.kilari
@ 2014-04-15 16:36   ` Julien Grall
  2014-04-23 14:16   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 16:36 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hi Vijay,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h
> new file mode 100644
> index 0000000..44b28a6
> --- /dev/null
> +++ b/xen/include/asm-arm/mmio.h
> @@ -0,0 +1,57 @@
> +/*
> + * xen/arch/arm/mmio.h

include/asm-arm/mmio.h

> + *
> + * ARM I/O handlers
> + *
> + * Copyright (c) 2011 Citrix Systems.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __ARCH_ARM_MMIO_H__
> +#define __ARCH_ARM_MMIO_H__

The line should be

#ifndef __ASM_ARM_MMIO_H__
#define __ASM_ARM_MMIO_H__

> +
> +#include <xen/lib.h>
> +#include <asm/processor.h>
> +#include <asm/regs.h>
> +
> +typedef struct
> +{
> +    struct hsr_dabt dabt;
> +    vaddr_t gva;
> +    paddr_t gpa;
> +} mmio_info_t;
> +
> +typedef int (*mmio_read_t)(struct vcpu *v, mmio_info_t *info);
> +typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info);
> +typedef int (*mmio_check_t)(struct vcpu *v, paddr_t addr);
> +
> +struct mmio_handler {
> +    mmio_check_t check_handler;
> +    mmio_read_t read_handler;
> +    mmio_write_t write_handler;
> +};
> +
> +extern const struct mmio_handler vgic_distr_mmio_handler;
> +extern const struct mmio_handler vuart_mmio_handler;
> +
> +extern int handle_mmio(mmio_info_t *info);
> +
> +#endif

#endif /* __ASM_ARM_MMIO_H__ */

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 02/16] xen/arm: make mmio handlers domain specific
  2014-04-15 11:17 ` [PATCH v3 02/16] xen/arm: make mmio handlers domain specific vijay.kilari
@ 2014-04-15 17:07   ` Julien Grall
  2014-04-23 14:27     ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-15 17:07 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank your for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c
> index ada1918..1a0be89 100644
> --- a/xen/arch/arm/io.c
> +++ b/xen/arch/arm/io.c
> @@ -18,29 +18,47 @@
>  
>  #include <xen/config.h>
>  #include <xen/lib.h>
> +#include <xen/spinlock.h>
> +#include <xen/sched.h>
>  #include <asm/current.h>
>  #include <asm/mmio.h>
>  
> -static const struct mmio_handler *const mmio_handlers[] =
> -{
> -    &vgic_distr_mmio_handler,
> -    &vuart_mmio_handler,
> -};
> -#define MMIO_HANDLER_NR ARRAY_SIZE(mmio_handlers)
> -
>  int handle_mmio(mmio_info_t *info)
>  {
>      struct vcpu *v = current;
>      int i;
> +    struct io_handler *mmio_handle = &v->domain->arch.io_handlers;
>  
> -    for ( i = 0; i < MMIO_HANDLER_NR; i++ )
> -        if ( mmio_handlers[i]->check_handler(v, info->gpa) )
> +    for ( i = 0; i < mmio_handle->num_entries; i++ )
> +    {
> +        if ( (info->gpa >= mmio_handle->mmio_handlers[i]->addr) &&
> +              info->gpa < (mmio_handle->mmio_handlers[i]->addr + mmio_handle->mmio_handlers[i]->size) )

The coding style request line length below 80 characters.

>              return info->dabt.write ?
> -                mmio_handlers[i]->write_handler(v, info) :
> -                mmio_handlers[i]->read_handler(v, info);
> -
> +                mmio_handle->mmio_handlers[i]->write_handler(v, info) :
> +                mmio_handle->mmio_handlers[i]->read_handler(v, info);
> +    }

Newline here for clarity.

>      return 0;
>  }
> +
> +void register_mmio_handler(struct domain *d, struct mmio_handler * handle)
> +{
> +    struct io_handler *handler = &d->arch.io_handlers;
> +
> +    BUG_ON(handler->num_entries >= MAX_IO_HANDLER);
> +
> +    spin_lock(&handler->lock);
> +    handler->mmio_handlers[handler->num_entries] = handle;
> +    handler->num_entries++;

If you plan to use spinlock only when a new entry is added, you need a
dsb(is) before increment num_entries. Smth like

handler->mmio_handlers[handler->num_entries] = handle;
dbs(sy);
handler->num_entries++;

> +    spin_unlock(&handler->lock);
> +}
> +
> +int domain_io_init(struct domain *d)
> +{
> +   spin_lock_init(&d->arch.io_handlers.lock);
> +   d->arch.io_handlers.num_entries = 0;

Newline here for clarity.

> +   return 0;
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 9c404fe..d36058a 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -35,6 +35,8 @@
>  /* Number of ranks of interrupt registers for a domain */
>  #define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
>  
> +static struct mmio_handler vgic_distr_mmio_handler;
> +
>  /*
>   * Rank containing GICD_<FOO><n> for GICD_<FOO> with
>   * <b>-bits-per-interrupt
> @@ -98,6 +100,10 @@ int domain_vgic_init(struct domain *d)
>      }
>      for (i=0; i<DOMAIN_NR_RANKS(d); i++)
>          spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
> +
> +    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
> +    vgic_distr_mmio_handler.size = PAGE_SIZE;
> +    register_mmio_handler(d, &vgic_distr_mmio_handler);

This is wrong. register_mmio_handler is directly copying the MMIO
handler. So updating addr will breaks other domains as the vgic.dbase
may differ.

I think my solution on V1 was correct. I.e smth like

register_mmio_handler(d, &vgic_distr_mmio_handler, address, size);

And your internal structure looks like:

struct io_handler
{
      ....
      struct
      {
          const struct mmio_handler *handler;
          paddr_t addr, size;
      } iohandlers[MAX_SIZE];
};

[..]

> diff --git a/xen/arch/arm/vuart.c b/xen/arch/arm/vuart.c
> index 895e5cd..f43f2e5 100644
> --- a/xen/arch/arm/vuart.c
> +++ b/xen/arch/arm/vuart.c
> @@ -44,6 +44,8 @@
>  
>  #define domain_has_vuart(d) ((d)->arch.vuart.info != NULL)
>  
> +static struct mmio_handler vuart_mmio_handler;
> +
>  int domain_vuart_init(struct domain *d)
>  {
>      ASSERT( !d->domain_id );
> @@ -59,6 +61,10 @@ int domain_vuart_init(struct domain *d)
>      if ( !d->arch.vuart.buf )
>          return -ENOMEM;
>  
> +    vuart_mmio_handler.addr = d->arch.vuart.info->base_addr;
> +    vuart_mmio_handler.size = d->arch.vuart.info->size;
> +    register_mmio_handler(d, &vuart_mmio_handler);
> +

Same here...

[..]
> --- a/xen/include/asm-arm/mmio.h
> +++ b/xen/include/asm-arm/mmio.h
> @@ -35,15 +35,22 @@ typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info);
>  typedef int (*mmio_check_t)(struct vcpu *v, paddr_t addr);
>  
>  struct mmio_handler {
> -    mmio_check_t check_handler;
> +    paddr_t addr;
> +    unsigned long size;

size should be paddr_t.

>      mmio_read_t read_handler;
>      mmio_write_t write_handler;
>  };
>  
> -extern const struct mmio_handler vgic_distr_mmio_handler;
> -extern const struct mmio_handler vuart_mmio_handler;
> +#define MAX_IO_HANDLER  16
> +struct io_handler {
> +    int num_entries;
> +    spinlock_t lock;
> +    struct mmio_handler *mmio_handlers[MAX_IO_HANDLER];
> +};
>  
>  extern int handle_mmio(mmio_info_t *info);
> +void register_mmio_handler(struct domain *d, struct mmio_handler * handle);

The IO handler will never be modified so it should be:

const struct mmio_handler *handler

> +int domain_io_init(struct domain *d);
>  
>  #endif
>  
> 

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 03/16] xen/arm: make sgi handling generic
  2014-04-15 11:17 ` [PATCH v3 03/16] xen/arm: make sgi handling generic vijay.kilari
@ 2014-04-15 17:51   ` Julien Grall
  2014-04-15 17:57     ` Julien Grall
  2014-04-23 14:31     ` Ian Campbell
  0 siblings, 2 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 17:51 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> move all the hw specific sgi handling functionality
> to one function and use it.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/gic.c        |   36 +++++++++++++++++++++++++++---------
>  xen/include/asm-arm/gic.h |    4 ++++
>  2 files changed, 31 insertions(+), 9 deletions(-)
> 
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 7faa0e9..d5cc931 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -480,21 +480,39 @@ void __init gic_init(void)
>      spin_unlock(&gic.lock);
>  }
>  
> -void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi)
> +void send_sgi(const cpumask_t *online_mask, enum gic_sgi sgi, uint8_t irqmode)

You would rename the function in send_SGI to stay consistent with the
other functions.

This function has to be static because you are only using it internally.

The first parameter "online_mask" is confusing. I would rename it in
"cpumask".


>  {
>      unsigned int mask = 0;
> +
> +    switch(irqmode)

switch ( ... )

> +    {
> +    case SGI_TARGET_OTHERS:
> +        GICD[GICD_SGIR] = GICD_SGI_TARGET_OTHERS | sgi;
> +        break;
> +    case SGI_TARGET_SELF:
> +        GICD[GICD_SGIR] = GICD_SGI_TARGET_SELF | sgi;
> +        break;
> +    case SGI_TARGET_LIST:
> +        mask = gic_cpu_mask(online_mask);
> +        GICD[GICD_SGIR] = GICD_SGI_TARGET_LIST |
> +                          (mask<<GICD_SGI_TARGET_SHIFT) | sgi;
> +        break;
> +    default:
> +         gdprintk(XENLOG_WARNING, "Wrong sgi irq mode for sgi %x\n", sgi);

You can't use gdprintk here as the function may not be used by guest.

You should replace by dprintk(...). Even better a BUG_ON as this should
be never reached.

[..]

>  void smp_send_state_dump(unsigned int cpu)
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 5d8f7f1..d03b490 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -50,6 +50,10 @@
>  #define GICD_SPENDSGIRN (0xF2C/4)
>  #define GICD_ICPIDR2    (0xFE8/4)
>  
> +#define SGI_TARGET_LIST    0
> +#define SGI_TARGET_OTHERS  1
> +#define SGI_TARGET_SELF    2
> +

You don't need to export it. It's used internally...

I would also use an enum as we know it's bound.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call
  2014-04-15 11:17 ` [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call vijay.kilari
@ 2014-04-15 17:52   ` Julien Grall
  2014-04-23 14:32   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 17:52 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> othercpu parameter in do_sgi is unused
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Acked-by: Julien Grall <julien.grall@linaro.org>

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 03/16] xen/arm: make sgi handling generic
  2014-04-15 17:51   ` Julien Grall
@ 2014-04-15 17:57     ` Julien Grall
  2014-04-23 14:31     ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 17:57 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/15/2014 06:51 PM, Julien Grall wrote:
>>  void smp_send_state_dump(unsigned int cpu)
>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>> index 5d8f7f1..d03b490 100644
>> --- a/xen/include/asm-arm/gic.h
>> +++ b/xen/include/asm-arm/gic.h
>> @@ -50,6 +50,10 @@
>>  #define GICD_SPENDSGIRN (0xF2C/4)
>>  #define GICD_ICPIDR2    (0xFE8/4)
>>  
>> +#define SGI_TARGET_LIST    0
>> +#define SGI_TARGET_OTHERS  1
>> +#define SGI_TARGET_SELF    2
>> +
> 
> You don't need to export it. It's used internally...

I forgot that it means to be used with both V2 and V3...

My remarks stay unchanged for the enum things.

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-15 11:17 ` [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality vijay.kilari
@ 2014-04-15 18:35   ` Julien Grall
  2014-04-23 14:55     ` Ian Campbell
  2014-04-28 11:48     ` Vijay Kilari
  2014-04-15 21:00   ` Julien Grall
  2014-04-23 14:52   ` Ian Campbell
  2 siblings, 2 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 18:35 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> +/* Access to the GIC Distributor registers through the fixmap */
> +#define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
> +#define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1))
> +#define GICH ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICH))
> +
> +/* Global state */
> +static struct {
> +    paddr_t dbase;       /* Address of distributor registers */
> +    paddr_t cbase;       /* Address of CPU interface registers */
> +    paddr_t hbase;       /* Address of virtual interface registers */
> +    paddr_t vbase;       /* Address of virtual cpu interface registers */
> +    unsigned int lines;  /* Number of interrupts (SPIs + PPIs + SGIs) */
> +    struct dt_irq maintenance; /* IRQ maintenance */
> +    unsigned int cpus;
> +} gic;
> +
> +static struct gic_hw_operations gic_ops;
> +
> +static uint8_t nr_lrs;

As the number of LRs is store in gic_hw_operations, you don't need this one.

> +
> +/* The GIC mapping of CPU interfaces does not necessarily match the
> + * logical CPU numbering. Let's use mapping as returned by the GIC
> + * itself
> + */
> +static DEFINE_PER_CPU(u8, gic_cpu_id);
> +
> +/* Maximum cpu interface per GIC */
> +#define NR_GIC_CPU_IF 8
> +
> +static unsigned int gicv2_cpu_mask(const cpumask_t *cpumask)
> +{
> +    unsigned int cpu;
> +    unsigned int mask = 0;
> +    cpumask_t possible_mask;
> +
> +    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
> +    for_each_cpu(cpu, &possible_mask)

I know that coding style error was there before ... can you change it to

for_each_cpu( ... )

> +    {
> +        ASSERT(cpu < NR_GIC_CPU_IF);
> +        mask |= per_cpu(gic_cpu_id, cpu);
> +    }
> +
> +    return mask;
> +}

[..]

> +static void gicv2_dump_state(struct vcpu *v)
> +{
> +    int i;
> +    if ( v == current )
> +    {
> +        for ( i = 0; i < nr_lrs; i++ )
> +            printk("   HW_LR[%d]=%x\n", i, GICH[GICH_LR + i]);
> +    } else {

}
else
{

[..]

> +static struct dt_irq * gicv2_maintenance_irq(void)
> +{
> +    return &gic.maintenance;
> +}

I have a serie which drop dt_struct and changes IRQW routing. It would
be nice if you can rebase your code on top of it now. I don't think it
will change heavily.

See git://xenbits.xen.org/people/julieng/xen-unstable.git branch
interrupt-mgmt-v3

[..]

>  static void gic_irq_enable(struct irq_desc *desc)
>  {
> -    int irq = desc->irq;
>      unsigned long flags;
>  
>      spin_lock_irqsave(&desc->lock, flags);
> @@ -147,20 +112,19 @@ static void gic_irq_enable(struct irq_desc *desc)
>      desc->status &= ~IRQ_DISABLED;
>      dsb();
>      /* Enable routing */
> -    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
> +    gic_hw_ops->gic_irq_ops->enable(desc);

This is not the right way to use gic_irq_ops. You should directly
assigned this structure to desc->handler.

I guess you don't do it because you have the desc->status and gic_lock
locking which is common.

IHMO, you have to let the GICv{2,3} drivers handling their own lock for
the hardware access.

>      spin_unlock(&gic_lock);
>      spin_unlock_irqrestore(&desc->lock, flags);
>  }
>  
>  static void gic_irq_disable(struct irq_desc *desc)
>  {
> -    int irq = desc->irq;
>      unsigned long flags;
>  
>      spin_lock_irqsave(&desc->lock, flags);
>      spin_lock(&gic_lock);
>      /* Disable routing */
> -    GICD[GICD_ICENABLER + irq / 32] = (1u << (irq % 32));
> +    gic_hw_ops->gic_irq_ops->disable(desc);
>      desc->status |= IRQ_DISABLED;
>      spin_unlock(&gic_lock);
>      spin_unlock_irqrestore(&desc->lock, flags);

Same here.

> @@ -186,16 +150,15 @@ static void gic_host_irq_end(struct irq_desc *desc)
>  {
>      int irq = desc->irq;
>      /* Lower the priority */
> -    GICC[GICC_EOIR] = irq;
> +    gic_hw_ops->gic_irq_ops->end(desc);
>      /* Deactivate */
> -    GICC[GICC_DIR] = irq;
> +    gic_hw_ops->deactivate_irq(irq);
>  }

>  static void gic_guest_irq_end(struct irq_desc *desc)
>  {
> -    int irq = desc->irq;
>      /* Lower the priority of the IRQ */
> -    GICC[GICC_EOIR] = irq;
> +    gic_hw_ops->gic_irq_ops->end(desc);
>      /* Deactivation happens in maintenance interrupt / via GICV */
>  }

Same here.

> @@ -215,6 +178,7 @@ static hw_irq_controller gic_host_irq_type = {
>      .end = gic_host_irq_end,
>      .set_affinity = gic_irq_set_affinity,
>  };
> +

Spurious change?

>  static hw_irq_controller gic_guest_irq_type = {
>      .typename = "gic",
>      .startup = gic_irq_startup,
> @@ -235,27 +199,7 @@ static void gic_set_irq_properties(unsigned int irq, bool_t level,
>                                     const cpumask_t *cpu_mask,
>                                     unsigned int priority)
>  {
> -    volatile unsigned char *bytereg;
> -    uint32_t cfg, edgebit;
> -    unsigned int mask = gic_cpu_mask(cpu_mask);
> -
> -    /* Set edge / level */
> -    cfg = GICD[GICD_ICFGR + irq / 16];
> -    edgebit = 2u << (2 * (irq % 16));
> -    if ( level )
> -        cfg &= ~edgebit;
> -    else
> -        cfg |= edgebit;
> -    GICD[GICD_ICFGR + irq / 16] = cfg;
> -
> -    /* Set target CPU mask (RAZ/WI on uniprocessor) */
> -    bytereg = (unsigned char *) (GICD + GICD_ITARGETSR);
> -    bytereg[irq] = mask;
> -
> -    /* Set priority */
> -    bytereg = (unsigned char *) (GICD + GICD_IPRIORITYR);
> -    bytereg[irq] = priority;
> -
> +   return gic_hw_ops->set_irq_property(irq, level, cpu_mask, priority);

You don't need to return as gic_set_irq_properties is a void function.
Also why did you drop in plural in the callback name? It should be name
set_irq_properties.

[..]

> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index eba41ee..2387e38 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -43,12 +43,41 @@
>  #define SGI_TARGET_OTHERS  1
>  #define SGI_TARGET_SELF    2
>  
> +#define GICH_LR_PENDING    1
> +#define GICH_LR_ACTIVE     2
> +

Prefixing by GICH_ is confusing. I though we were using it for to set
the value in the hardware. Can you rename it?

> +#define GICH_HCR_EN       (1 << 0)
> +#define GICH_HCR_UIE      (1 << 1)
> +#define GICH_HCR_LRENPIE  (1 << 2)
> +#define GICH_HCR_NPIE     (1 << 3)
> +#define GICH_HCR_VGRP0EIE (1 << 4)
> +#define GICH_HCR_VGRP0DIE (1 << 5)
> +#define GICH_HCR_VGRP1EIE (1 << 6)
> +#define GICH_HCR_VGRP1DIE (1 << 7)
> +

You dropped this lines in patch #5 and re-add here.
Please don't drop them on patch #5.

>  #ifndef __ASSEMBLY__
>  #include <xen/device_tree.h>
> +#include <xen/irq.h>
>  
>  #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
>                          DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")
>  
> +/*
> + * Decode LR register content and populate below struct.

IHMO, the second part of the description (after the "and") is not useful.

[..]

> +struct gic_hw_operations {
> +    /* GIC version */
> +    enum gic_version hw_version;
> +    /* Number of GIC lines supported */
> +    unsigned int nr_lines;
> +    /* Number of LR registers */
> +    unsigned int nr_lrs;
> +    /* Maintenance irq is derived from dt node. Fetch from gic driver */
> +    struct dt_irq * (*get_maintenance_irq)(void);
> +    /* Save GIC registers */
> +    void (*save_state)(struct vcpu *);
> +    /* Restore GIC registers */
> +    void (*restore_state)(struct vcpu *);

Does restore state will modify the content of vcpu? If not, please add
const.

> +    /* Dump GIC LR register information */
> +    void (*dump_state)(struct vcpu *);

Same question here.

> +    /* Map MMIO region of GIC and get GIC address information */
> +    int (*gicv_setup)(struct domain *);
> +
> +    /* hw_irq_controller for enable/disable/eoi irq */

The hw_irq_controller should contains every callbacks. (see my previous
remark on it).

> +    hw_irq_controller *gic_irq_ops;

const hw_irq_controller *gic_irq_ops;

> +
> +    /* Deactivate/reduce priority of irq */
> +    void (*deactivate_irq)(int);
> +    /* Ack IRQ and return irq id */
> +    unsigned int (*ack_irq)(void);
> +    /* Set IRQ property */
> +    void (*set_irq_property)(unsigned int irq, bool_t level,
> +                            const cpumask_t *cpu_mask,
> +                            unsigned int priority);
> +    /* Send SGI */
> +    void (*send_sgi)(const cpumask_t *online_mask,
> +                         enum gic_sgi sgi, uint8_t irqmode);

Misaligned?

> +    /* Disable CPU physical and virtual interfaces */
> +    void (*disable_interface)(void);
> +    /* Update LR with state and priority */
> +    void (*update_lr)(int lr, struct pending_irq *, unsigned int state);

Update LR won't modify pending_irq, right? If so, please add const.

Also you are mixing named and unamed argument. Can you name every arguments?

> +    /* Update HCR status register */
> +    void (*update_hcr_status)(uint32_t flag, bool_t set);
> +    /* Clear LR register */
> +    void (*clear_lr)(int lr);
> +    /* Read LR register and populate gic_lr structure */
> +    void (*read_lr)(int lr, struct gic_lr *);
> +    /* Write LR register from gic_lr structure */
> +    void (*write_lr)(int lr, struct gic_lr *);

write_lr won't modify pending_irq, right? If so, please add const.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver
  2014-04-15 11:17 ` [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver vijay.kilari
@ 2014-04-15 18:41   ` Julien Grall
  2014-04-23 14:57     ` Ian Campbell
  2014-04-23 14:58   ` Ian Campbell
  1 sibling, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-15 18:41 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for your patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 999bbdd..be1b084 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -8,6 +8,7 @@
>  #include <asm/p2m.h>
>  #include <asm/vfp.h>
>  #include <asm/mmio.h>
> +#include <asm/gic.h>
>  #include <public/hvm/params.h>
>  #include <xen/serial.h>
>  
> @@ -260,8 +261,7 @@ struct arch_vcpu
>      uint32_t csselr;
>      register_t vmpidr;
>  
> -    uint32_t gic_hcr, gic_vmcr, gic_apr;
> -    uint32_t gic_lr[64];

I would add a comment such as "GIC state" here.

> +    union gic_state_data gic;
>      uint64_t event_mask;
>      uint64_t lr_mask;

[..]

> +struct gic_v2 {
> +    uint32_t hcr, vmcr;
> +    uint32_t apr;
> +    uint32_t lr[64];
> +};
> +

Even if with the name you know it's GICv2. Can you document quickly the
structure?

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 09/16] xen/arm: use device api to detect GIC version
  2014-04-15 11:17 ` [PATCH v3 09/16] xen/arm: use device api to detect GIC version vijay.kilari
@ 2014-04-15 18:49   ` Julien Grall
  2014-04-23 15:01   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 18:49 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
> index 7c63bae..1e62dd9 100644
> --- a/xen/arch/arm/gic-v2.c
> +++ b/xen/arch/arm/gic-v2.c
> @@ -31,6 +31,7 @@
>  #include <asm/p2m.h>
>  #include <asm/domain.h>
>  #include <asm/platform.h>
> +#include <asm/device.h>
>  
>  #include <asm/gic_v2_defs.h>
>  #include <asm/gic.h>
> @@ -276,20 +277,10 @@ static void __cpuinit gicv2_hyp_disable(void)
>  }
>  
>  /* Set up the GIC */
> -void __init gicv2_init(void)
> +int __init gicv2_init(struct dt_device_node *node, const void *data)

The function can be static.

[..]

> +static const char * const gicv2_dt_compat[] __initconst =
> +{
> +    "arm,cortex-a15-gic",
> +    "arm,cortex-a9-gic",
> +    NULL
> +};
> +
> +DT_DEVICE_START(gicv2, "GIC", DEVICE_GIC)

I would use "GICv2" instead of "GIC".

> +        .compatible = gicv2_dt_compat,
> +        .init = gicv2_init,
> +DT_DEVICE_END
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index ce21ef6..4a86c42 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -31,6 +31,7 @@
>  #include <asm/p2m.h>
>  #include <asm/domain.h>
>  #include <asm/platform.h>
> +#include <asm/device.h>
>  
>  #include <asm/gic.h>
>  
> @@ -264,8 +265,29 @@ int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
>  /* Set up the GIC */
>  void __init gic_init(void)
>  {
> -    gicv2_init();
> +    int rc;
> +    struct dt_device_node *node;
> +    uint8_t num_gics = 0;

bool_t gic_present?

> +
>      spin_lock_init(&gic_lock);
> +
> +    dt_for_each_device_node(dt_host, node)

dt_for_each_device_node( ... )

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file
  2014-04-15 11:17 ` [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file vijay.kilari
@ 2014-04-15 19:10   ` Julien Grall
  2014-04-17  6:48     ` Vijay Kilari
  2014-05-07 15:03   ` Julien Grall
  1 sibling, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-15 19:10 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 4830b5d..f73247d 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -30,6 +30,7 @@
>  #include <asm/mmio.h>
>  #include <asm/gic_v2_defs.h>
>  #include <asm/gic.h>
> +#include <asm/vgic.h>
>  
>  #define REG(n) (n/4)
>  
> @@ -69,7 +70,7 @@ static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
>      int rank = REG_RANK_NR(b, n);
>  
>      if ( rank == 0 )
> -        return &v->arch.vgic.private_irqs;
> +        return v->arch.vgic.private_irqs;
>      else if ( rank <= DOMAIN_NR_RANKS(v->domain) )
>          return &v->domain->arch.vgic.shared_irqs[rank - 1];
>      else
> @@ -117,9 +118,14 @@ void domain_vgic_free(struct domain *d)
>  int vcpu_vgic_init(struct vcpu *v)
>  {
>      int i;
> -    memset(&v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
>  
> -    spin_lock_init(&v->arch.vgic.private_irqs.lock);
> +    v->arch.vgic.private_irqs = xzalloc(struct vgic_irq_rank);
> +    if ( v->arch.vgic.private_irqs == NULL )
> +      return -ENOMEM;
> +
> +    memset(v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
> +

xzalloc will zeroed the structure for you. You don't need to zeroed
again. BTW the sizeof was wrong here :).

> +    spin_lock_init(&v->arch.vgic.private_irqs->lock);
>  
>      memset(&v->arch.vgic.pending_irqs, 0, sizeof(v->arch.vgic.pending_irqs));
>      for (i = 0; i < 32; i++)
> @@ -130,7 +136,7 @@ int vcpu_vgic_init(struct vcpu *v)
>  
>      /* For SGI and PPI the target is always this CPU */
>      for ( i = 0 ; i < 8 ; i++ )
> -        v->arch.vgic.private_irqs.itargets[i] =
> +        v->arch.vgic.private_irqs->itargets[i] =
>                (1<<(v->vcpu_id+0))
>              | (1<<(v->vcpu_id+8))
>              | (1<<(v->vcpu_id+16))
> @@ -142,6 +148,12 @@ int vcpu_vgic_init(struct vcpu *v)
>      return 0;
>  }
>  
> +int vcpu_vgic_free(struct vcpu *v)
> +{
> +    xfree(v->arch.vgic.private_irqs);

Can you add a newline here for clarity?

> +    return 0;
> +}
> +
>  #define vgic_lock(v)   spin_lock_irq(&(v)->domain->arch.vgic.lock)
>  #define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock)
>  

[..]

> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> new file mode 100644
> index 0000000..104a87d
> --- /dev/null
> +++ b/xen/include/asm-arm/vgic.h
> @@ -0,0 +1,40 @@
> +/*
> + * ARM Virtual Generic Interrupt Controller support
> + *
> + * Ian Campbell <ian.campbell@citrix.com>
> + * Copyright (c) 2011 Citrix Systems.
> + *

Hmmm... where does the copyright come from?

> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __ASM_ARM_VGIC_H__
> +#define __ASM_ARM_VGIC_H__
> +
> +/* Represents state corresponding to a block of 32 interrupts */
> +struct vgic_irq_rank {
> +    spinlock_t lock; /* Covers access to all other members of this struct */
> +    uint32_t ienable, iactive, ipend, pendsgi;
> +    uint32_t icfg[2];
> +    uint32_t ipriority[8];
> +    uint32_t itargets[8];
> +};
> +
> +extern int vcpu_vgic_free(struct vcpu *v);
> +#endif

#endif /* __ASM_ARM_VGIC_H__ */

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver
  2014-04-15 11:17 ` [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver vijay.kilari
@ 2014-04-15 20:05   ` Julien Grall
  2014-04-23 15:12   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 20:05 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:

[..]

> +/*
> + * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
> + * <b>-bits-per-interrupt.
> + */
> +#define REG_RANK_INDEX(b, n) ((n) & ((b)-1))
> +
> +/*
> + * Returns rank corresponding to a GICD_<FOO><n> register for
> + * GICD_<FOO> with <b>-bits-per-interrupt.
> + */
> +static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)

I think all the functions have to be named vgic_v2_...

It will improve readability for backtrace.

> +{
> +    int rank = REG_RANK_NR(b, n);
> +    return vgic_get_irqrank(v, rank);
> +}
> +
> +static int vgic_read_priority(struct vcpu *v, int irq)
> +{
> +   int idx = irq >> 2;
> +   struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx);

New line here for clarity.

> +   return byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, irq & 0x3);
> +}

[..]

> +static int vgic_vcpu_init(struct vcpu *v)
> +{
> +    int i;
> +
> +    /* For SGI and PPI the target is always this CPU */
> +    for ( i = 0 ; i < 8 ; i++ )
> +        v->arch.vgic.private_irqs->itargets[i] =
> +              (1<<(v->vcpu_id+0))
> +            | (1<<(v->vcpu_id+8))
> +            | (1<<(v->vcpu_id+16))
> +            | (1<<(v->vcpu_id+24));

Newline here for clarity.

> +    return 0;
> +}
> +
> +static int vgic_domain_init(struct domain *d)
> +{
> +    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
> +    vgic_distr_mmio_handler.size = PAGE_SIZE;
> +    register_mmio_handler(d, &vgic_distr_mmio_handler);
> +    return 0;
> +}
> +
> +static struct vgic_ops ops = {

This function as to be const.

> +    .vgic_vcpu_init   = vgic_vcpu_init,
> +    .vgic_domain_init = vgic_domain_init,
> +    .read_priority    = vgic_read_priority,
> +};
> +
> +int vgic_v2_init(struct domain *d)
> +{

What domain is used for if you unconditionally register the ops?

> +    register_vgic_ops(&ops);

I think you need to pass the domain here. And register the ops per domain.

Will be easier for a later change to support V2 on V3.

> +    return 0;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 7e258ae..f487784 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -28,29 +28,20 @@
>  #include <asm/current.h>
>  
>  #include <asm/mmio.h>
> -#include <asm/gic_v2_defs.h>
>  #include <asm/gic.h>
>  #include <asm/vgic.h>
>  
> -#define REG(n) (n/4)
>  
> -static struct mmio_handler vgic_distr_mmio_handler;
> +static struct vgic_ops *vgic_ops;

static const ?

>  
> -/*
> - * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
> - * <b>-bits-per-interrupt.
> - */
> -#define REG_RANK_INDEX(b, n) ((n) & ((b)-1))
> -
> -/*
> - * Returns rank corresponding to a GICD_<FOO><n> register for
> - * GICD_<FOO> with <b>-bits-per-interrupt.
> - */
> -static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
> +void register_vgic_ops(struct vgic_ops *ops)

const struct vgic_ops *ops ?

>  {
> -    int rank = REG_RANK_NR(b, n);
> +   vgic_ops = ops;
> +}
>  
> -    if ( rank == 0 )
> +struct vgic_irq_rank *vgic_get_irqrank(struct vcpu *v, int rank)
> +{
> +    if ( rank == 0 ) /* Rank 0 is nothing but GICR registers in GICv3 */
>          return v->arch.vgic.private_irqs;
>      else if ( rank <= DOMAIN_NR_RANKS(v->domain) )
>          return &v->domain->arch.vgic.shared_irqs[rank - 1];
> @@ -61,7 +52,6 @@ static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
>  int domain_vgic_init(struct domain *d)
>  {
>      int i;
> -
>      d->arch.vgic.ctlr = 0;
>  
>      /* Currently nr_lines in vgic and gic doesn't have the same meanings
> @@ -72,21 +62,34 @@ int domain_vgic_init(struct domain *d)
>      else
>          d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
>  
> +    if ( gic_hw_version() == GIC_V2 )
> +        vgic_v2_init(d);
> +    else
> +        panic("No VGIC found\n");

panic when a domain is creating is not the right thing to do... You
should return here.

> +
>      d->arch.vgic.shared_irqs =
>          xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d));
> +    if ( d->arch.vgic.shared_irqs == NULL )
> +        return -ENOMEM;
> +

Which version of Xen are you using? A patch to check shared_irqs has
been upstreamed a while ago.


> +    for ( i = 0; i < DOMAIN_NR_RANKS(d); i++ )
> +        spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
> +

Why did you move this code earlier?

> +    vgic_ops->vgic_domain_init(d);
> +

I think vgic_domain_init should be called at the end. Not in middle of
the initialization...

>      d->arch.vgic.pending_irqs =
>          xzalloc_array(struct pending_irq, d->arch.vgic.nr_lines);
> -    for (i=0; i<d->arch.vgic.nr_lines; i++)
> +    if ( d->arch.vgic.pending_irqs == NULL )
> +    {
> +        xfree(d->arch.vgic.shared_irqs);
> +        return -ENOMEM;
> +    }
> +

Patch already sent to fix this.

> +    for ( i = 0; i < d->arch.vgic.nr_lines; i++)

for ( ... )

>      {
>          INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].inflight);
>          INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].lr_queue);
>      }
> -    for (i=0; i<DOMAIN_NR_RANKS(d); i++)
> -        spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
> -
> -    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
> -    vgic_distr_mmio_handler.size = PAGE_SIZE;
> -    register_mmio_handler(d, &vgic_distr_mmio_handler);
>      return 0;
>  }
>  
> @@ -105,9 +108,13 @@ int vcpu_vgic_init(struct vcpu *v)
>        return -ENOMEM;
>  
>      memset(v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
> -

Spurious change?

>      spin_lock_init(&v->arch.vgic.private_irqs->lock);
>  
> +    if ( vgic_ops )
> +       vgic_ops->vgic_vcpu_init(v);
> +    else
> +       panic("No VGIC ops found\n");
> +

No panic here... vgic_ops has been set before. So why should you check here?


Same question as for vgic_vpcu_init. Why did you move this code early?

>      memset(&v->arch.vgic.pending_irqs, 0, sizeof(v->arch.vgic.pending_irqs));
>      for (i = 0; i < 32; i++)
>      {
> @@ -115,13 +122,6 @@ int vcpu_vgic_init(struct vcpu *v)
>          INIT_LIST_HEAD(&v->arch.vgic.pending_irqs[i].lr_queue);
>      }
>  
> -    /* For SGI and PPI the target is always this CPU */
> -    for ( i = 0 ; i < 8 ; i++ )
> -        v->arch.vgic.private_irqs->itargets[i] =
> -              (1<<(v->vcpu_id+0))
> -            | (1<<(v->vcpu_id+8))
> -            | (1<<(v->vcpu_id+16))
> -            | (1<<(v->vcpu_id+24));
>      INIT_LIST_HEAD(&v->arch.vgic.inflight_irqs);
>      INIT_LIST_HEAD(&v->arch.vgic.lr_pending);
>      spin_lock_init(&v->arch.vgic.lock);
> @@ -135,7 +135,7 @@ int vcpu_vgic_free(struct vcpu *v)
>      return 0;
>  }
>  
> -static uint32_t byte_read(uint32_t val, int sign, int offset)
> +uint32_t byte_read(uint32_t val, int sign, int offset)

If you export this function, please rename it.

Also, I think it can be moved static inline in vgic.h.

>  {
>      int byte = offset & 0x3;
>  
> @@ -147,7 +147,7 @@ static uint32_t byte_read(uint32_t val, int sign, int offset)
>      return val;
>  }
>  
> -static void byte_write(uint32_t *reg, uint32_t var, int offset)
> +void byte_write(uint32_t *reg, uint32_t var, int offset)

Same remarks here.

[..]

>  struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
>  {
>      struct pending_irq *n;
> @@ -666,10 +229,9 @@ void vgic_clear_pending_irqs(struct vcpu *v)
>  
>  void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq)
>  {
> -    int idx = irq >> 2, byte = irq & 0x3;
>      uint8_t priority;
> -    struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx);
> -    struct pending_irq *iter, *n = irq_to_pending(v, irq);
> +    struct pending_irq *iter;
> +    struct pending_irq  *n = irq_to_pending(v, irq);
>      unsigned long flags;
>      bool_t running;
>  
> @@ -682,7 +244,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq)
>          return;
>      }
>  
> -    priority = byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, byte);
> +    priority = vgic_ops->read_priority(v, irq);
>  
>      n->irq = irq;
>      set_bit(GIC_IRQ_GUEST_PENDING, &n->status);
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index f9d6549..187846e 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -28,6 +28,12 @@ struct vgic_irq_rank {
>      uint32_t itargets[8];
>  };
>  
> +struct vgic_ops {

Please describe every callbacks of this structure.

> +    int (*vgic_vcpu_init)(struct vcpu *v);
> +    int (*vgic_domain_init)(struct domain *d);
> +    int (*read_priority)(struct vcpu *v, int irq);

I saw this function is assuming that some locks are used. Please write a
comment about it.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-15 11:17 ` [PATCH v3 13/16] xen/arm: Add support for GIC v3 vijay.kilari
@ 2014-04-15 20:43   ` Julien Grall
  2014-04-17  7:09     ` Vijay Kilari
  2014-04-17  9:57   ` Julien Grall
  2014-04-23 17:01   ` Ian Campbell
  2 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-15 20:43 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Add support for GIC v3 specification System register access(SRE)
> is enabled to access cpu and virtual interface regiseters based

s/regiseters/registers/

> on kernel GICv3 driver.

I think you miss some newline in this paragraph.

What are the major changes with GICv3 from the kernel? Do you have a
commit ID? (Will be easier to sync if an issue is found).

> 
> This patch adds only basic v3 support.

What does mean basic? What is missing? What is there?

> Does not support Interrupt Translation support (ITS)
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/Makefile                 |    2 +-
>  xen/arch/arm/gic-v3.c                 |  967 +++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/arm64/processor.h |   14 +
>  xen/include/asm-arm/domain.h          |    6 +
>  xen/include/asm-arm/gic.h             |   15 +
>  xen/include/asm-arm/gic_v3_defs.h     |  198 +++++++
>  6 files changed, 1201 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 20f59f4..39166aa 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -10,7 +10,7 @@ obj-y += vpsci.o
>  obj-y += domctl.o
>  obj-y += sysctl.o
>  obj-y += domain_build.o
> -obj-y += gic.o gic-v2.o
> +obj-y += gic.o gic-v3.o gic-v2.o

Shouldn't it only build for ARMv8 (i.e ARM64 on Xen)?

ICH_* sysreg are not defined on ARM32...

>  obj-y += io.o
>  obj-y += irq.o
>  obj-y += kernel.o
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> new file mode 100644
> index 0000000..8625e0c
> --- /dev/null
> +++ b/xen/arch/arm/gic-v3.c
> @@ -0,0 +1,967 @@
> +/*
> + * xen/arch/arm/gic-v3.c
> + *
> + * ARM Generic Interrupt Controller support v3 version
> + * based on xen/arch/arm/gic-v2.c and kernel GICv3 driver
> + * 
> + * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
> + * Copyright (c) 2014 Cavium Inc.

If it's based on the Linux drivers, I think you have to keep Marc's
Copyright.

> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/config.h>
> +#include <xen/lib.h>
> +#include <xen/init.h>
> +#include <xen/cpu.h>
> +#include <xen/mm.h>
> +#include <xen/irq.h>
> +#include <xen/sched.h>
> +#include <xen/errno.h>
> +#include <xen/serial.h>
> +#include <xen/softirq.h>
> +#include <xen/list.h>
> +#include <xen/device_tree.h>
> +#include <xen/delay.h>
> +#include <asm/p2m.h>
> +#include <asm/domain.h>
> +#include <asm/platform.h>
> +
> +#include <asm/gic_v3_defs.h>
> +#include <asm/gic.h>
> +#include <asm/io.h>
> +#include <asm/device.h>
> +
> +static struct gic_hw_operations gic_ops;
> +
> +struct rdist_region {
> +    paddr_t rdist_base;
> +    paddr_t rdist_base_size;
> +    void __iomem *map_rdist_base;
> +};
> +
> +/* Global state */
> +static struct {
> +    paddr_t dbase;            /* Address of distributor registers */
> +    paddr_t dbase_size;
> +    void __iomem *map_dbase;  /* Mapped address of distributor registers */
> +    struct rdist_region *rdist_regions;
> +    u32  rdist_stride;
> +    unsigned int rdist_count; /* Number of rdist regions count */
> +    unsigned int lines;       /* Number of interrupts (SPIs + PPIs + SGIs) */
> +    struct dt_irq maintenance;
> +}gic;

} gic;

> +
> +/* per-cpu re-distributor base */
> +static DEFINE_PER_CPU(void __iomem*, rbase);
> +
> +static uint8_t nr_lrs;

Same remarks as GICv2, nr_lrs is already stored in gic_ops.

> +static uint32_t nr_priorities;

Why nr_priorities can be part of your structure?

> +static void gicv3_dist_wait_for_rwp(void)
> +{
> +    gicv3_do_wait_for_rwp(GICD);
> +}
> +
> +static void gicv3_redist_wait_for_rwp(void)
> +{
> +    gicv3_do_wait_for_rwp(GICD_RDIST_BASE);
> +}
> +
> +static void gicv3_wait_for_rwp(int irq)
> +{
> +    if ( irq < NR_LOCAL_IRQS )
> +         gicv3_redist_wait_for_rwp();
> +    else
> +         gicv3_dist_wait_for_rwp();
> +}
> +
> +static unsigned int gicv3_mask_cpu(const cpumask_t *cpumask)
> +{
> +    unsigned int cpu;
> +    cpumask_t possible_mask;
> +
> +    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
> +    cpu = cpumask_any(&possible_mask);

Newline for clarity here.

> +    return cpu;
> +}
> +
> +static void write_aprn_regs(union gic_state_data *d)
> +{
> +    ASSERT((nr_priorities > 4 && nr_priorities < 8));

Wouldn't it be better to check it at boot time?

> +    /* Write APRn register based on number of priorities
> +       plaform has implemented */
> +    switch ( nr_priorities )
> +    {
> +    case 7:
> +        WRITE_SYSREG32(d->v3.apr0[2], ICH_AP0R2_EL2);
> +        WRITE_SYSREG32(d->v3.apr1[2], ICH_AP1R2_EL2);
> +        /* Fall through */
> +    case 6:
> +        WRITE_SYSREG32(d->v3.apr0[1], ICH_AP0R1_EL2);
> +        WRITE_SYSREG32(d->v3.apr1[1], ICH_AP1R1_EL2);
> +        /* Fall through */
> +    case 5:
> +        WRITE_SYSREG32(d->v3.apr0[0], ICH_AP0R0_EL2);
> +        WRITE_SYSREG32(d->v3.apr1[0], ICH_AP1R0_EL2);
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static void read_aprn_regs(union gic_state_data *d)
> +{
> +    ASSERT((nr_priorities > 4 && nr_priorities < 8));
> +    /* Read APRn register based on number of priorities
> +       plaform has implemented */
> +    switch ( nr_priorities )
> +    {
> +    case 7:
> +        d->v3.apr0[2] = READ_SYSREG32(ICH_AP0R2_EL2);
> +        d->v3.apr1[2] = READ_SYSREG32(ICH_AP1R2_EL2);
> +        /* Fall through */
> +    case 6:
> +        d->v3.apr0[1] = READ_SYSREG32(ICH_AP0R1_EL2);
> +        d->v3.apr1[1] = READ_SYSREG32(ICH_AP1R1_EL2);
> +        /* Fall through */
> +    case 5:
> +        d->v3.apr0[0] = READ_SYSREG32(ICH_AP0R0_EL2);
> +        d->v3.apr1[0] = READ_SYSREG32(ICH_AP1R0_EL2);
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +static void gicv3_save_state(struct vcpu *v)
> +{
> +    int i;
> +
> +    /* No need for spinlocks here because interrupts are disabled around
> +     * this call and it only accesses struct vcpu fields that cannot be
> +     * accessed simultaneously by another pCPU.
> +     */

That made me think you have the same message in GICv2 (Patch #7). It
would be better to move it in common code and add a description on
callback in gic.h.

> +    for ( i = 0; i < nr_lrs; i++)
> +        v->arch.gic.v3.lr[i] = gich_read_lr(i);
> +
> +    read_aprn_regs(&v->arch.gic); 
> +    v->arch.gic.v3.vmcr = READ_SYSREG32(ICH_VMCR_EL2);
> +}
> +
> +static void gicv3_restore_state(struct vcpu *v)
> +{
> +    int i;
> +
> +    for ( i = 0; i < nr_lrs; i++)
> +        gich_write_lr(i, v->arch.gic.v3.lr[i]);
> +
> +    write_aprn_regs(&v->arch.gic);
> +
> +    WRITE_SYSREG32(v->arch.gic.v3.vmcr, ICH_VMCR_EL2);
> +}
> +
> +static void gicv3_dump_state(struct vcpu *v)
> +{
> +    int i;

Newline is required between block declaration and code.

> +    if ( v == current )

[..]

> +static void gicv3_disable_irq(struct irq_desc *irqd)
> +{
> +    int irq = irqd->irq;
> +    uint32_t val;

Same here.

> +    /* Disable routing */
> +    if ( irq < NR_GIC_LOCAL_IRQS )
> +    {
> +        val = 1u << irq;
> +        writel_relaxed(val, GICD_RDIST_SGI_BASE + GICR_ICENABLER0);
> +    } else {
> +        val = 1u << (irq % 32);
> +        writel_relaxed(val, GICD + GICD_ICENABLER + ((irq / 32) * 4));
> +    }
> +}
> +
> +static void gicv3_eoi_irq(struct irq_desc *irqd)
> +{
> +    int irq = irqd->irq;

Same here.

> +    /* Lower the priority */
> +    WRITE_SYSREG32(irq, ICC_EOIR1_EL1);
> +}
> +
> +static void gicv3_dir_irq(int irq)
> +{
> +    /* Deactivate */
> +    WRITE_SYSREG32(irq, ICC_DIR_EL1);
> +}
> +
> +static unsigned int gicv3_ack_irq(void)
> +{
> +    return (READ_SYSREG32(ICC_IAR1_EL1) & GICC_IA_IRQ);
> +}
> +
> +
> +static u64 gic_mpidr_to_affinity(u64 mpidr)

I would rework this function to get a cpu in parameter and return the
affinity.

It will avoid many cpu_logical_map(cpu) in the code.

> +{
> +    u64 aff;
> +    /* Make sure we don't broadcast the interrupt */
> +     aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
> +            MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
> +            MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
> +            MPIDR_AFFINITY_LEVEL(mpidr, 0)) & ~GICD_IROUTER_SPI_MODE_ANY;
> +    return aff;
> +}
> +
> +/*
> + * - needs to be called with gic.lock held
> + * - needs to be called with a valid cpu_mask, ie each cpu in the mask has
> + * already called gic_cpu_init
> + */

Same comment as for save_state. I think this should move the definition
of the callback in gic.h

> +static void gicv3_set_irq_property(unsigned int irq, bool_t level,
> +                                   const cpumask_t *cpu_mask,
> +                                   unsigned int priority)
> +{
> +    uint32_t cfg, edgebit;
> +    u64 affinity;
> +    unsigned int cpu = gicv3_mask_cpu(cpu_mask);
> +
> +
> +    /* Set edge / level */
> +    if ( irq < NR_GIC_SGI )
> +        /* SGI's are always edge-triggered not need to call GICD_ICFGR0 */
> +        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR0);

Your comment suggests you don't need to call GICD_ICFGR0... but you are
calling it.

> +    else if ( irq < NR_GIC_LOCAL_IRQS )
> +        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR1);
> +    else
> +        cfg = readl_relaxed(GICD + GICD_ICFGR + (irq / 16) * 4);
> +

Rather than splitting with if/else stuff and calling readl_relaxed. I
would do

if ( irq < NR_GIC_SGI)
   mybase = GICD_RDIST_SGI_BASE + GICR_ICFGR0
else if (..)
   mybase = foo.
else ...

cfg = reald_relaxed(mybase):

> +    edgebit = 2u << (2 * (irq % 16));
> +    if ( level )
> +        cfg &= ~edgebit;
> +    else
> +        cfg |= edgebit;
> +
> +    if ( irq < NR_GIC_SGI )
> +       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR0);
> +    else if ( irq < NR_GIC_LOCAL_IRQS )
> +       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR1);
> +    else
> +       writel_relaxed(cfg, GICD + GICD_ICFGR + (irq / 16) * 4);

With my suggestion above, it will avoid another bunch of if/else here.

[..]

> +static void gicv3_enable_redist(void)
> +{
> +    u32 val;
> +    /* Wait for 1s */
> +    u32 count = 1000000;
> +
> +    /* Wake up this CPU redistributor */
> +    val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
> +    val &= ~GICR_WAKER_ProcessorSleep;
> +    writel_relaxed(val, GICD_RDIST_BASE + GICR_WAKER);
> +
> +    do {
> +         val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
> +         if ( !(val & GICR_WAKER_ChildrenAsleep) )
> +           break;
> +         cpu_relax();
> +         udelay(1);
> +    } while ( count-- );
> +
> +    if ( !count )
> +        gdprintk(XENLOG_WARNING, "Redist enable RWP timeout\n");

gdprintk is used for guest. At the time that enable_redist is called, no
guest is running.

Also, I think this function should return an error if you are not able
to enable redist and return an error gicv3_cpu_init which will propagate
to the common code.

> +}
> +
> +static int __init gicv3_populate_rdist(void)
> +{
> +    u64 mpidr = cpu_logical_map(smp_processor_id());
> +    u64 typer;
> +    uint32_t aff;
> +    int i;
> +    uint32_t reg;
> +
> +    aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
> +           MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
> +           MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
> +           MPIDR_AFFINITY_LEVEL(mpidr, 0));

Why can't you use gic_mpidr_to_affinity?

> +
> +    for ( i = 0; i < gic.rdist_count; i++ )
> +    {
> +        void __iomem *ptr = gic.rdist_regions[i].map_rdist_base;
> +
> +        reg = readl_relaxed(ptr + GICR_PIDR2);
> +        if ( (reg & GICR_PIDR2_ARCH_MASK) != GICR_PIDR2_GICV3 ) {
> +            dprintk(XENLOG_WARNING, "No redistributor present @%"PRIpaddr"\n",
> +                   (u64)ptr);
> +            break;
> +        }
> +
> +        do {
> +            typer = readq_relaxed(ptr + GICR_TYPER);
> +            if ( (typer >> 32) == aff )
> +            {
> +                this_cpu(rbase) = ptr;
> +                printk("CPU%d: Found redistributor in region %d\n",
> +                           smp_processor_id(), i);
> +                return 0;
> +            }
> +            if ( gic.rdist_stride ) {
> +                ptr += gic.rdist_stride;
> +            } else {
> +                ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
> +                if ( typer & GICR_TYPER_VLPIS )
> +                    ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
> +            }
> +        } while ( !(typer & GICR_TYPER_LAST) );
> +    }
> +
> +    dprintk(XENLOG_WARNING, "CPU%d: mpidr %"PRIpaddr" has no re-distributor!\n",
> +                  smp_processor_id(), mpidr);

What happen if you don't have re-distributor?

[..]

> +static void gicv3_clear_lr(int lr)
> +{
> +    gich_write_lr(lr, 0);
> +}
> +
> +static void gicv3_read_lr(int lr, struct gic_lr *lr_reg)
> +{
> +    u64 lrv;

Newline for clarity.

> +    lrv = gich_read_lr(lr);
> +    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
> +    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK; 
> +    lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK;
> +    lr_reg->state    = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
> +    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;
> +    lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;
> +}
> +
> +static void gicv3_write_lr(int lr_reg, struct gic_lr *lr)
> +{
> +    u64 lrv = 0;

Same here.

> +    lrv = ( ((u64)(lr->pirq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT) |
> +        ((u64)(lr->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT) |
> +        ((u64)(lr->priority & GICH_LR_PRIORITY_MASK) << GICH_LR_PRIORITY_SHIFT) |
> +        ((u64)(lr->state & GICH_LR_STATE_MASK) << GICH_LR_STATE_SHIFT) |
> +        ((u64)(lr->hw_status & GICH_LR_HW_MASK)  << GICH_LR_HW_SHIFT)  |
> +        ((u64)(lr->grp & GICH_LR_GRP_MASK) << GICH_LR_GRP_SHIFT) );
> +    gich_write_lr(lr_reg, lrv);
> +}
> +
> +int gicv_v3_init(struct domain *d)

Don't need to export gicv_v3_init.

[..]

> +/* Set up the GIC */
> +static int __init gicv3_init(struct dt_device_node *node,
> +                                       const void *data)

Something wrong in the alignment?

> +{
> +    struct rdist_region *rdist_regs;
> +    int res, i;
> +    uint32_t reg;
> +
> +    dt_device_set_used_by(node, DOMID_XEN);
> +
> +    res = dt_device_get_address(node, 0, &gic.dbase, &gic.dbase_size);
> +    if ( res || !gic.dbase  || (gic.dbase & ~PAGE_MASK) ||
> +       (gic.dbase_size & ~PAGE_MASK) )
> +        panic("GIC: Cannot find a valid address for the distributor");
> +
> +    gic.map_dbase = ioremap_nocache(gic.dbase, gic.dbase_size);
> +    if ( !gic.map_dbase )
> +        panic("Failed to ioremap for GIC distributor\n");
> +
> +    reg = readl_relaxed(GICD + GICD_PIDR2);
> +    if ( (reg & GICD_PIDR2_ARCH_MASK) != GICD_PIDR2_GICV3 )
> +        panic("GIC: no distributor detected, giving up\n"); 
> +
> +    gic_ops.hw_version = GIC_V3;
> + 
> +    if ( !dt_property_read_u32(node, "#redistributor-regions",
> +                &gic.rdist_count) )
> +        gic.rdist_count = 1;
> +
> +    if ( gic.rdist_count > MAX_RDIST_COUNT )
> +        panic("GIC: Number of redistributor regions is more than \
> +               MAX_RDIST_COUNT (Increase MAX_RDIST_COUNT!!)\n");
> +
> +    rdist_regs = xzalloc_array(struct rdist_region, gic.rdist_count);
> +    if ( !rdist_regs )
> +        panic("GIC: no distributor detected, giving up\n");
> +
> +    for ( i = 0; i < gic.rdist_count; i++ ) {

for ( ... )
{

> +        u64 rdist_base, rdist_size;
> +
> +        res = dt_device_get_address(node, 1 + i, &rdist_base, &rdist_size);
> +        if ( res || !rdist_base)

if ( ... )

> +            panic("No rdist base found\n");
> +
> +        rdist_regs[i].rdist_base = rdist_base;
> +        rdist_regs[i].rdist_base_size = rdist_size;
> +    }
> +
> +    if ( !dt_property_read_u32(node, "redistributor-stride", &gic.rdist_stride) )
> +        gic.rdist_stride = 0x0;
> +
> +    gic.rdist_regions= rdist_regs;
> + 
> +    res = dt_device_get_irq(node, 0, &gic.maintenance);
> +    if ( res )
> +        panic("GIC: Cannot find the maintenance IRQ");
> +
> +    /* Set the GIC as the primary interrupt controller */
> +    dt_interrupt_controller = node;
> +
> +    for ( i = 0; i < gic.rdist_count; i++ ) {

for ( ... )

> +        /* map dbase & rdist regions */
> +        gic.rdist_regions[i].map_rdist_base =
> +                ioremap_nocache(gic.rdist_regions[i].rdist_base,
> +                          gic.rdist_regions[i].rdist_base_size);
> +
> +        if ( !gic.rdist_regions[i].map_rdist_base )
> +            panic("Failed to ioremap for GIC redistributor\n");
> +    }
> +
> +    printk("GIC initialization:\n"

Can you replace GIC by GICv3 in the print message?

> +              "        gic_dist_addr=%"PRIpaddr"\n"

Please correctly align to printk.

> +              "        gic_dist_size=%"PRIpaddr"\n"
> +              "        gic_dist_mapaddr=%"PRIpaddr"\n"
> +              "        gic_rdist_regions=%d\n"
> +              "        gic_rdist_stride=%x\n"
> +              "        gic_rdist_base=%"PRIpaddr"\n"
> +              "        gic_rdist_base_size=%"PRIpaddr"\n"
> +              "        gic_rdist_base_mapaddr=%"PRIpaddr"\n"
> +              "        gic_maintenance_irq=%u\n",
> +              gic.dbase, gic.dbase_size, (u64)gic.map_dbase, gic.rdist_count,
> +              gic.rdist_stride, gic.rdist_regions[0].rdist_base,
> +              gic.rdist_regions[0].rdist_base_size,
> +              (u64)gic.rdist_regions[0].map_rdist_base, gic.maintenance.irq);
> +
> +    gicv3_dist_init();
> +    gicv3_cpu_init();
> +    gicv3_hyp_init();
> +
> +    /* Register hw ops*/
> +    register_gic_ops(&gic_ops);

Newline here for clarity.

> +    return 0;
> +}
> +
> +static const char * const gicv3_dt_compat[] __initconst =
> +{
> +    "arm,gic-v3",
> +    NULL
> +};
> +
> +DT_DEVICE_START(gicv3, "GIC", DEVICE_GIC)
> +        .compatible = gicv3_dt_compat,
> +        .init = gicv3_init,
> +DT_DEVICE_END
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/asm-arm/arm64/processor.h b/xen/include/asm-arm/arm64/processor.h
> index 5bf0867..3ecdc70 100644
> --- a/xen/include/asm-arm/arm64/processor.h
> +++ b/xen/include/asm-arm/arm64/processor.h
> @@ -3,6 +3,20 @@
>  
>  #ifndef __ASSEMBLY__
>  
> +/*
> + * Macros to extract affinity level. picked from kernel
> + */
> +
> +#define MPIDR_LEVEL_BITS_SHIFT  3
> +#define MPIDR_LEVEL_BITS        (1 << MPIDR_LEVEL_BITS_SHIFT)
> +#define MPIDR_LEVEL_MASK        ((1 << MPIDR_LEVEL_BITS) - 1)
> +
> +#define MPIDR_LEVEL_SHIFT(level) \
> +         (((1 << level) >> 1) << MPIDR_LEVEL_BITS_SHIFT)
> +
> +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
> +         ((mpidr >> MPIDR_LEVEL_SHIFT(level)) & MPIDR_LEVEL_MASK)
> +

It's not arm64 depend, this should go in asm-arm/processor.h

>  /* Anonymous union includes both 32- and 64-bit names (e.g., r0/x0). */
>  
>  #define __DECL_REG(n64, n32) union {            \
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index ccd9640..c27085b 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -151,6 +151,12 @@ struct arch_domain
>          /* Base address for guest GIC */
>          paddr_t dbase; /* Distributor base address */
>          paddr_t cbase; /* CPU base address */
> +        /* GIC V3 addressing */
> +        paddr_t dbase_size; /* Distributor base size */
> +        paddr_t rbase[MAX_RDIST_COUNT];      /* Re-Distributor base address */
> +        paddr_t rbase_size[MAX_RDIST_COUNT]; /* Re-Distributor size */
> +        uint32_t rdist_stride;               /* Re-Distributor stride */
> +        int rdist_count;                     /* No. of Re-Distributors */

As the GICv3 code won't work on ARM32, this should not be compiled on
32-bits.

>      } vgic;
>  
>      struct vuart {
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 7489684..3c37120 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -18,6 +18,12 @@
>  #ifndef __ASM_ARM_GIC_H__
>  #define __ASM_ARM_GIC_H__
>  
> +#define SZ_64K  0x00010000
> +

Please don't harcode like that. This should go in common code.

xen/include/xen/lib.h might be a good candidate.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-15 11:17 ` [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality vijay.kilari
  2014-04-15 18:35   ` Julien Grall
@ 2014-04-15 21:00   ` Julien Grall
  2014-04-23 14:52   ` Ian Campbell
  2 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-15 21:00 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijay,

A couple of things I've noticed while reviewing this series.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> +static void gicv2_write_lr(int lr, struct gic_lr *lr_reg)
> +{
> +    uint32_t lrv = 0;

Newline here.

> +    lrv = ( ((lr_reg->pirq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT)  |
> +            ((lr_reg->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT)   |
> +            ((uint32_t)(lr_reg->priority & GICH_LR_PRIORITY_MASK) << GICH_LR_PRIORITY_SHIFT) |
> +            ((uint32_t)(lr_reg->state & GICH_LR_STATE_MASK) << GICH_LR_STATE_SHIFT) |
> +            ((uint32_t)(lr_reg->hw_status & GICH_LR_HW_MASK)  << GICH_LR_HW_SHIFT)  |
> +            ((uint32_t)(lr_reg->grp & GICH_LR_GRP_MASK) << GICH_LR_GRP_SHIFT) );
> +
> +    GICH[GICH_LR + lr] = lrv;
> +}

[..]

> +struct gic_hw_operations {

Some of these functions require locks. You have to specified here which
lock is required.

That will avoid headache for people who are planning to implement new
GIC driver.

> +    /* GIC version */
> +    enum gic_version hw_version;
> +    /* Number of GIC lines supported */
> +    unsigned int nr_lines;
> +    /* Number of LR registers */
> +    unsigned int nr_lrs;
> +    /* Maintenance irq is derived from dt node. Fetch from gic driver */
> +    struct dt_irq * (*get_maintenance_irq)(void);
> +    /* Save GIC registers */
> +    void (*save_state)(struct vcpu *);
> +    /* Restore GIC registers */
> +    void (*restore_state)(struct vcpu *);
> +    /* Dump GIC LR register information */
> +    void (*dump_state)(struct vcpu *);
> +    /* Map MMIO region of GIC and get GIC address information */
> +    int (*gicv_setup)(struct domain *);
> +
> +    /* hw_irq_controller for enable/disable/eoi irq */
> +    hw_irq_controller *gic_irq_ops;
> +
> +    /* Deactivate/reduce priority of irq */
> +    void (*deactivate_irq)(int);
> +    /* Ack IRQ and return irq id */
> +    unsigned int (*ack_irq)(void);

This name of this function is not clear for me. I would rename into

read_irq_and_ack (maybe the and_ack is not necessary).

> +    /* Set IRQ property */
> +    void (*set_irq_property)(unsigned int irq, bool_t level,
> +                            const cpumask_t *cpu_mask,
> +                            unsigned int priority);
> +    /* Send SGI */
> +    void (*send_sgi)(const cpumask_t *online_mask,
> +                         enum gic_sgi sgi, uint8_t irqmode);
> +    /* Disable CPU physical and virtual interfaces */
> +    void (*disable_interface)(void);
> +    /* Update LR with state and priority */
> +    void (*update_lr)(int lr, struct pending_irq *, unsigned int state);
> +    /* Update HCR status register */
> +    void (*update_hcr_status)(uint32_t flag, bool_t set);
> +    /* Clear LR register */
> +    void (*clear_lr)(int lr);
> +    /* Read LR register and populate gic_lr structure */
> +    void (*read_lr)(int lr, struct gic_lr *);
> +    /* Write LR register from gic_lr structure */
> +    void (*write_lr)(int lr, struct gic_lr *);
> +    /* Read VMCR priority */
> +    unsigned int (*read_vmcr_priority)(void);
> +    /* Secondary CPU init */
> +    void (*secondary_init)(void);

I would return an int here. I saw a panic on GICv3, and I don't think
it's acceptable for secondary CPUs. I can be used during CPU hotplug.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 11/16] xen/arm: move vgic defines to vgic header file
  2014-04-15 11:17 ` [PATCH v3 11/16] xen/arm: move vgic defines to vgic " vijay.kilari
@ 2014-04-16 17:01   ` Julien Grall
  2014-04-23 15:07     ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-16 17:01 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> gic.h contains defines of vgic. Move these to vgic
> header file. Also move inline functions and defines
> in vgic.c to vgic.h

Can you explain in the commit message, why you need to move theses
functions in the header?

> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

[..]

> -extern int gic_hw_version(void);
> -
> -extern int domain_vgic_init(struct domain *d);
> -extern void domain_vgic_free(struct domain *d);
> -
> -extern int vcpu_vgic_init(struct vcpu *v);
> -
> -extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq);
> -extern void vgic_clear_pending_irqs(struct vcpu *v);
>  extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq);
> +extern int gic_hw_version(void);

Why did you change the place of gic_hw_version in the code?

>  /* Program the GIC to route an interrupt with a dt_irq */
>  extern void gic_route_dt_irq(const struct dt_irq *irq,
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index 104a87d..f9d6549 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -17,6 +17,7 @@
>  
>  #ifndef __ASM_ARM_VGIC_H__
>  #define __ASM_ARM_VGIC_H__
> +#include <xen/bitops.h>
>  
>  /* Represents state corresponding to a block of 32 interrupts */
>  struct vgic_irq_rank {
> @@ -27,6 +28,52 @@ struct vgic_irq_rank {
>      uint32_t itargets[8];
>  };
>  
> +/* Number of ranks of interrupt registers for a domain */
> +#define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)

[..]

> +static inline int REG_RANK_NR(int b, uint32_t n)

[..]

> +static inline int is_vcpu_running(struct domain *d, int vcpuid)


The name of the 2 functions and 1 define are too generic. It was fine
internally but not to be exported.

Please find new names

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file
  2014-04-15 19:10   ` Julien Grall
@ 2014-04-17  6:48     ` Vijay Kilari
  0 siblings, 0 replies; 107+ messages in thread
From: Vijay Kilari @ 2014-04-17  6:48 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Wed, Apr 16, 2014 at 12:40 AM, Julien Grall <julien.grall@linaro.org> wrote:
>> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
>> new file mode 100644
>> index 0000000..104a87d
>> --- /dev/null
>> +++ b/xen/include/asm-arm/vgic.h
>> @@ -0,0 +1,40 @@
>> +/*
>> + * ARM Virtual Generic Interrupt Controller support
>> + *
>> + * Ian Campbell <ian.campbell@citrix.com>
>> + * Copyright (c) 2011 Citrix Systems.
>> + *
>
> Hmmm... where does the copyright come from?
vgic.c was authored by Ian. So I retained the same for header file as well

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-15 20:43   ` Julien Grall
@ 2014-04-17  7:09     ` Vijay Kilari
  2014-04-17  8:58       ` Ian Campbell
  2014-04-17  9:02       ` Julien Grall
  0 siblings, 2 replies; 107+ messages in thread
From: Vijay Kilari @ 2014-04-17  7:09 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Wed, Apr 16, 2014 at 2:13 AM, Julien Grall <julien.grall@linaro.org> wrote:
> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> Add support for GIC v3 specification System register access(SRE)
>> is enabled to access cpu and virtual interface regiseters based
>
> s/regiseters/registers/
>
>> on kernel GICv3 driver.
>
> I think you miss some newline in this paragraph.
>
> What are the major changes with GICv3 from the kernel? Do you have a
> commit ID? (Will be easier to sync if an issue is found).
>
I have taken only some helper functions from Kernel driver.
I will update with commit-id in my next version.

>>
>> This patch adds only basic v3 support.
>
> What does mean basic? What is missing? What is there?

Still some more features are missing. I will plan for these later
Ex:
Locality Specific Peripheral Interrupts (LPIs)
Interrupt Translation Services (ITS)

>> Does not support Interrupt Translation support (ITS)
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>> ---
>> + *
>> + * ARM Generic Interrupt Controller support v3 version
>> + * based on xen/arch/arm/gic-v2.c and kernel GICv3 driver
>> + *
>> + * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
>> + * Copyright (c) 2014 Cavium Inc.
>
> If it's based on the Linux drivers, I think you have to keep Marc's
> Copyright.
I have taken only few helper functions from kernel driver.
So I have mentioned based on.

>> +                if ( typer & GICR_TYPER_VLPIS )
>> +                    ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
>> +            }
>> +        } while ( !(typer & GICR_TYPER_LAST) );
>> +    }
>> +
>> +    dprintk(XENLOG_WARNING, "CPU%d: mpidr %"PRIpaddr" has no re-distributor!\n",
>> +                  smp_processor_id(), mpidr);
>
> What happen if you don't have re-distributor?
>
  I think, we can't handle SGI & PPI's. As configuration and handling of these
is done in GICR region. May be I can change it to BUG_ON

> [..]
>

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-17  7:09     ` Vijay Kilari
@ 2014-04-17  8:58       ` Ian Campbell
  2014-04-17  9:02       ` Julien Grall
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-17  8:58 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Thu, 2014-04-17 at 12:39 +0530, Vijay Kilari wrote:
> >> + *
> >> + * ARM Generic Interrupt Controller support v3 version
> >> + * based on xen/arch/arm/gic-v2.c and kernel GICv3 driver
> >> + *
> >> + * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
> >> + * Copyright (c) 2014 Cavium Inc.
> >
> > If it's based on the Linux drivers, I think you have to keep Marc's
> > Copyright.
> I have taken only few helper functions from kernel driver.

Marc's copyright on that work still applies regardless of it only being
a "few" functions, it should be retained.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-17  7:09     ` Vijay Kilari
  2014-04-17  8:58       ` Ian Campbell
@ 2014-04-17  9:02       ` Julien Grall
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-17  9:02 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 04/17/2014 08:09 AM, Vijay Kilari wrote:
>>> +                if ( typer & GICR_TYPER_VLPIS )
>>> +                    ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
>>> +            }
>>> +        } while ( !(typer & GICR_TYPER_LAST) );
>>> +    }
>>> +
>>> +    dprintk(XENLOG_WARNING, "CPU%d: mpidr %"PRIpaddr" has no re-distributor!\n",
>>> +                  smp_processor_id(), mpidr);
>>
>> What happen if you don't have re-distributor?
>>
>   I think, we can't handle SGI & PPI's. As configuration and handling of these
> is done in GICR region. May be I can change it to BUG_ON

Please, no BUG_ON. As I said previously, you have to propagate the error
code. It will be useful for CPU hotplug later.

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 14/16] xen/arm: Add virtual GICv3 support
  2014-04-15 11:17 ` [PATCH v3 14/16] xen/arm: Add virtual GICv3 support vijay.kilari
@ 2014-04-17  9:27   ` Julien Grall
  2014-04-24 10:37     ` Ian Campbell
  2014-04-24 10:30   ` Ian Campbell
  1 sibling, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-17  9:27 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

Hello Vijaya,

Thank you for the patch.

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Add virtual GICv3 driver support
> 
> This patch adds only basic v3 support.
> Does not support Interrupt Translation support (ITS)
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/Makefile             |    2 +-
>  xen/arch/arm/vgic-v3.c            |  835 +++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic.c               |    4 +-
>  xen/include/asm-arm/gic_v3_defs.h |    2 +
>  xen/include/asm-arm/vgic.h        |    9 +-
>  5 files changed, 849 insertions(+), 3 deletions(-)
> 
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 39166aa..d269191 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -26,7 +26,7 @@ obj-y += smpboot.o
>  obj-y += smp.o
>  obj-y += shutdown.o
>  obj-y += traps.o
> -obj-y += vgic.o vgic-v2.o
> +obj-y += vgic.o vgic-v3.o vgic-v2.o

Same as for patch #13, vgic-v3 should only be compiled on armv8 (i.e ARM64).

>  obj-y += vtimer.o
>  obj-y += vuart.o
>  obj-y += hvm.o
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> new file mode 100644
> index 0000000..e3d773a
> --- /dev/null
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -0,0 +1,835 @@
> +/*
> + * xen/arch/arm/vgic-v3.c
> + *
> + * ARM Virtual Generic Interrupt Controller v3 support
> + * based on xen/arch/arm/vgic.c
> + *
> + * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
> + * Copyright (c) 2014 Cavium Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/bitops.h>
> +#include <xen/config.h>
> +#include <xen/lib.h>
> +#include <xen/init.h>
> +#include <xen/softirq.h>
> +#include <xen/irq.h>
> +#include <xen/sched.h>
> +
> +#include <asm/current.h>
> +#include <asm/device.h>
> +
> +#include <asm/mmio.h>
> +#include <asm/gic_v3_defs.h>
> +#include <asm/gic.h>
> +#include <asm/vgic.h>
> +
> +#define REG(n) (n)

Why an id macro?

> +/*
> + * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
> + * <b>-bits-per-interrupt.
> + */
> +/* Shift n >> 2 to make it byte register diff */
> +#define REG_RANK_INDEX(b, n) (((n) >> 2) & ((b)-1))
> +
> +/*
> + * Returns rank corresponding to a GICD_<FOO><n> register for
> + * GICD_<FOO> with <b>-bits-per-interrupt.
> + */
> +static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
> +{
> +    int rank;
> +
> +    /* divide by 4 to make it byte size register difference
> +      as n is difference of 4 byte size register */
> +    n = n >> 2;
> +    rank  = REG_RANK_NR(b, n);
> +
> +    return vgic_get_irqrank(v, rank);
> +}
> +
> +static int vgic_read_priority(struct vcpu *v, int irq)
> +{
> +   struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, irq);

Newline here for more clarity.

> +   return byte_read(rank->ipriority[REG_RANK_INDEX(8, irq)], 0, irq & 0x3);
> +}
> +
> +static int __vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info,
> +           uint32_t offset)
> +{

You have to check the size for all cases in this function...

> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +    int gicr_reg = REG(offset);
> +    u64 mpidr;
> +    u64 aff;
> +
> +    switch ( gicr_reg )
> +    {
> +    case GICR_CTLR:
> +        /* We have implemented LPI's, read zero */

You are not constant in the comment. Did you implement LPI or not?

> +        goto read_as_zero;
> +    case GICR_IIDR:
> +        *r = GICR_IIDR_VAL;
> +        return 1;
> +    case GICR_TYPER:
> +        mpidr = cpu_logical_map(smp_processor_id());

Why do you use the physical CPU ID? Should not it be the vCPU ID?

FYI, VCPU are not necessary mapped 1:1 and can be moved.

> +        aff  = mpidr & ((1 << 24) - 1);
> +        aff |= (mpidr >> 8) & (0xffUL << 24);
> +        aff = aff << 32;
> +        aff = (aff | ((u64)smp_processor_id() << 8));
> +        aff = (aff | (0x9UL << 0));
> +        *r = aff;

You only use aff, mpidr in this case, right? If so, please define the
both variable in the case.

> +        return 1;
> +    case GICR_STATUSR:
> +        /* Not implemented */
> +        goto read_as_zero;

This register contains usefull bits for guest debugging. It would be
nice to implemented in the future.

> +    case GICR_WAKER:
> +        /* Not implemented */

Please explain why it's not implemented.

> +        goto read_as_zero;
> +    case GICR_SETLPIR:
> +    case GICR_CLRLPIR:
> +        /* WO return fail */
> +        return 0;

Returning 0 here will inject a data abort exception to the guest. I
don't think we want that.

>From the documentation (see 5.1.2, if you need more details I can
explain you privately) read on write-only register should be read 0.

There some other manner to handle it, but we don't care for now.

> +    case GICR_PROPBASER:
> +        /* LPI's not implemented */
> +        goto read_as_zero;

Hrmmm... you are read_as_zero is only able to handle 32-bits (see
dabt.size != 2). But PROPBASER is a 64 bit register.

> +    case GICR_PENDBASER:
> +        /* LPI's not implemented */
> +        goto read_as_zero;
> +    case GICR_INVLPIR:
> +    case GICR_INVALLR:
> +        /* WO return fail*/

Same remarks as GICR_SETLPIR...

> +        return 0;
> +    case GICR_SYNCR:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        /* RO */
> +        /* Return as not busy */
> +        *r = GICR_SYNCR_NOT_BUSY;

Please explain why this value.

> +        return 1;
> +    case GICR_MOVLPIR:
> +    case GICR_MOVALLR:
> +        /* WO */

Same remarks as GICR_SETLPIR.

> +        return 0;
> +    case GICR_PIDR7... GICR_PIDR0:
> +        *r = GICR_PIDR0_GICV3;

Hrrmmm... no. PIDR1 should return 0xB (on ARM implementation)...

> +         return 1;
> +    default:
> +        printk("vGICR: read r%d offset %#08x\n not found", dabt.reg, offset);
> +        return 0;
> +    }
> +bad_width:
> +    printk("vGICD: bad read width %d r%d offset %#08x\n",
> +           dabt.size, dabt.reg, offset);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +read_as_zero:
> +    if ( dabt.size != 2 ) goto bad_width;

As said previously this function only works for 32 bit access.

> +    *r = 0;
> +    return 1;
> +}
> +
> +static int __vgic_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info,
> +          uint32_t offset)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +    int gicr_reg = REG(offset);
> +
> +    switch ( gicr_reg )
> +    {
> +    case GICR_CTLR:
> +        /* We do not implement LPI's, read zero */
> +        goto write_ignore;
> +    case GICR_IIDR:
> +    case GICR_TYPER:
> +        /* RO */
> +        goto write_ignore;

Why do you sometime gather multiple case, and sometimes not? I would
prefer if you don't gather, as you do most of the times...

> +    case GICR_STATUSR:
> +        /* Not implemented */
> +        goto write_ignore;
> +    case GICR_WAKER:
> +        /* Not implemented */
> +        goto write_ignore;
> +    case GICR_SETLPIR:
> +        /* Not implemented */
> +        goto write_ignore;
> +    case GICR_CLRLPIR:
> +        /* Not implemented */
> +        goto write_ignore;

For all the case before, can you explain in a comment why you didn't
implement it?

> +    case GICR_PROPBASER:
> +        /* LPI is not implemented */
> +        goto write_ignore;
> +    case GICR_PENDBASER:
> +        /* LPI is not implemented */
> +        goto write_ignore;
> +    case GICR_INVLPIR:
> +        return 1;
> +    case GICR_INVALLR:
> +        return 1;
> +    case GICR_SYNCR:
> +        /* RO */
> +        goto write_ignore;
> +    case GICR_MOVLPIR:
> +        return 1;
> +    case GICR_MOVALLR:
> +        return 1;
> +    case GICR_PIDR7... GICR_PIDR0:
> +        /* RO */
> +        goto write_ignore;
> +    default:
> +        printk("vGICR: write r%d offset %#08x\n not found", dabt.reg, offset);
> +        return 0;
> +    }
> +bad_width:
> +    printk("vGICR: bad write width %d r%d=%"PRIregister" offset %#08x\n",
> +           dabt.size, dabt.reg, *r, offset);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +write_ignore:
> +    if ( dabt.size != 2 ) goto bad_width;

This as the same issue as __vrdist_mmio_write.

[..]

> +static int vgic_rdistr_sgi_mmio_write(struct vcpu *v, mmio_info_t *info,
> +           uint32_t offset)
> +{

This function seems to be a copy of vgic_distr_mmio_write (with some
printk removed???? and s/GICD/GICR). Can you avoid duplicate code? It
will be easier to maintain.

[..]

> +    case GICR_ICENABLER0:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICENABLER0);
> +        if ( rank == NULL ) goto write_ignore;
> +        vgic_lock_rank(v, rank);
> +        rank->ienable &= ~*r;
> +        vgic_unlock_rank(v, rank);

You should call vgic_disable_irqs here.

> +        return 1;
> +    case GICR_ISPENDR0:
> +        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;

printk....

> +        return 0;
> +    case GICR_ICPENDR0:
> +        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;

printk...

> +        return 0;
> +    case GICR_ISACTIVER0:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISACTIVER0);
> +        if ( rank == NULL ) goto write_ignore;
> +        vgic_lock_rank(v, rank);
> +        rank->iactive &= ~*r;
> +        vgic_unlock_rank(v, rank);
> +        return 1;
> +    case GICR_ICACTIVER0:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICACTIVER0);
> +        if ( rank == NULL) goto write_ignore;
> +        vgic_lock_rank(v, rank);
> +        rank->iactive &= ~*r;
> +        vgic_unlock_rank(v, rank);
> +        return 1;
> +    case GICR_IPRIORITYR0...GICR_IPRIORITYR7:
> +        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
> +        rank = vgic_irq_rank(v, 8, gicr_reg - GICR_IPRIORITYR0);
> +        if ( rank == NULL) goto write_ignore;
> +        vgic_lock_rank(v, rank);
> +        if ( dabt.size == 2 )
> +            rank->ipriority[REG_RANK_INDEX(8, gicr_reg - GICR_IPRIORITYR0)] = *r;
> +        else
> +            byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicr_reg - GICR_IPRIORITYR0)],
> +                       *r, offset);
> +        vgic_unlock_rank(v, rank);
> +        return 1;
> +    case GICR_ICFGR0:
> +        /* RO */
	   goto write_ignore;

And please specify why it's read-only.

> +    case GICR_ICFGR1:
> +        goto write_ignore;

Same remarks as GICR_ICFGR0.

> +static int vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info)
> +{
> +    uint32_t offset;
> +
> +    if ( !v->domain->arch.vgic.rdist_stride )
> +        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
> +    else
> +        offset = info->gpa & 0x1FFFF;
> +
> +    if ( offset < SZ_64K )
> +       return __vgic_rdistr_mmio_read(v, info, offset);
> +    else if ( (offset - SZ_64K) < SZ_64K )
> +       return vgic_rdistr_sgi_mmio_read(v, info, (offset - SZ_64K));
> +    else
> +       dprintk(XENLOG_WARNING, "vGICR: wrong gpa read address %"PRIpaddr"\n",
> +               info->gpa);

gdprintk?

> +    return 0;
> +}
> +
> +static int vgic_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info)
> +{
> +    uint32_t offset;
> +
> +    if ( !v->domain->arch.vgic.rdist_stride )
> +        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
> +    else
> +        offset = info->gpa & 0x1FFFF;
> +
> +    if ( offset < SZ_64K )
> +       return __vgic_rdistr_mmio_write(v, info, offset);
> +    else if ( (offset - SZ_64K) < SZ_64K )
> +       return vgic_rdistr_sgi_mmio_write(v, info, (offset - SZ_64K));
> +    else
> +       dprintk(XENLOG_WARNING, "vGICR: wrong gpa write %"PRIpaddr"\n",
> +               info->gpa);
> +    return 0;
> +}
> +
> +static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +    struct vgic_irq_rank *rank;
> +    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
> +    int gicd_reg = REG(offset);
> +

Is it a copy of vgic v2 distr + few registers?

> +    switch ( gicd_reg )
> +    {
> +    case GICD_CTLR:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        vgic_lock(v);
> +        *r = v->domain->arch.vgic.ctlr;
> +        vgic_unlock(v);
> +        return 1;
> +    case GICD_TYPER:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        /* No secure world support for guests. */
> +        vgic_lock(v);
> +        *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS )
> +            |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES );
> +        vgic_unlock(v);
> +        return 1;
> +    case GICD_STATUSR:
> +        /* Not implemented */
> +        goto read_as_zero;
> +    case GICD_IIDR:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        /*
> +         * XXX Do we need a JEP106 manufacturer ID?
> +         * Just use the physical h/w value for now
> +         */
> +        *r = GICD_IIDR_VAL;
> +        return 1;
> +    /* Implementation defined -- read as zero */
> +    case REG(0x020) ... REG(0x03c):

Please move the comment after the case.

Also can you give a name to this register? For clarity.

[..]

> +    case GICD_PIDR7... GICD_PIDR0:
> +        /* GICv3 identification value */
> +        *r = GICD_PIDR0_GICV3;

Same as GICR_PIDR* in rdist read. This is wrong.

> +        return 1;
> +    case REG(0x00c):
> +    case REG(0x044):
> +    case REG(0x04c):
> +    case REG(0x05c) ... REG(0x07c):
> +    case REG(0xf30) ... REG(0x5fcc):
> +    case REG(0x8000) ... REG(0xbfcc):
> +    case REG(0xc000) ... REG(0xffcc):
> +        printk("vGICD: read unknown 0x00c .. 0xfcc r%d offset %#08x\n",
> +               dabt.reg, offset);

What are those registers?

> +        goto read_as_zero;
> +
> +    default:
> +        printk("vGICD: unhandled read r%d offset %#08x\n",
> +               dabt.reg, offset);
> +        return 0;
> +    }
> +
> +bad_width:
> +    dprintk(XENLOG_ERR, "vGICD: bad read width %d r%d offset %#08x\n",
> +           dabt.size, dabt.reg, offset);
> +    domain_crash_synchronous();
> +    return 0;
> +
> +read_as_zero:
> +    printk("vGICD: read as zero %d r%d offset %#08x\n",
> +           dabt.size, dabt.reg, offset);

You should remove this printk. It will call often.

> +    if ( dabt.size != 2 ) goto bad_width;
> +    *r = 0;
> +    return 1;
> +}
> +
> +static int vgic_distr_mmio_write(struct vcpu *v, mmio_info_t *info)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +    struct vgic_irq_rank *rank;
> +    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
> +    int gicd_reg = REG(offset);
> +    uint32_t tr;
> +
> +    switch ( gicd_reg )
> +    {
> +    case GICD_CTLR:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        /* Ignore all but the enable bit */
> +        v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE;
> +        return 1;
> +
> +    /* R/O -- write ignored */
> +    case GICD_TYPER:


goto write_ignore.

> +    case GICD_IIDR:
> +        goto write_ignore;
> +    case GICD_STATUSR:
> +        goto write_ignore;
> +    case GICD_SETSPI_NSR:
> +        goto write_ignore;
> +    case GICD_CLRSPI_NSR:
> +        goto write_ignore;
> +    case GICD_SETSPI_SR:
> +        goto write_ignore;
> +    case GICD_CLRSPI_SR:
> +        goto write_ignore;
> +    /* Implementation defined -- write ignored */
> +    case REG(0x020) ... REG(0x03c):
> +        printk("vGICD: write unknown 0x020 - 0x03c r%d offset %#08x\n",
> +               dabt.reg, offset);

Please move the comment after the case.

[..]

> +static int vgic_vcpu_init(struct vcpu *v)
> +{
> +    int i;
> +    u64 affinity;
> +
> +    /* For SGI and PPI the target is always this CPU */
> +    affinity = cpu_logical_map(v->vcpu_id);

vcpu_id != physical ID.

> +    for ( i = 0 ; i < 32 ; i++ )
> +        v->arch.vgic.private_irqs->irouter[i] = affinity;
> +    return 0;
> +}

[..]

> diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
> index 578832b..f7f7932 100644
> --- a/xen/include/asm-arm/gic_v3_defs.h
> +++ b/xen/include/asm-arm/gic_v3_defs.h
> @@ -94,6 +94,8 @@
>  #define GICD_PIDR2_ARCH_MASK          (0xf0)
>  #define GICR_PIDR2_ARCH_MASK          GICD_PIDR2_ARCH_MASK
>  #define GICR_SYNCR_NOT_BUSY           1
> +#define GICD_IIDR_VAL                 0x34c

What does mean this value? How does Linux behave when this ID register
is read?

> +#define GICR_IIDR_VAL                 GICD_IIDR_VAL
>  
>  #define GICR_CTLR       (0x0000)
>  #define GICR_IIDR       (0x0004)
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index 187846e..0de74eb 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -25,7 +25,10 @@ struct vgic_irq_rank {
>      uint32_t ienable, iactive, ipend, pendsgi;
>      uint32_t icfg[2];
>      uint32_t ipriority[8];
> -    uint32_t itargets[8];
> +    union {
> +        uint32_t itargets[8];
> +        uint64_t irouter[32];
> +   };

Can you add a comment why you use an union, and what VGIC version is
using what?

>  };
>  
>  struct vgic_ops {
> @@ -51,6 +54,9 @@ static inline int REG_RANK_NR(int b, uint32_t n)
>  {
>      switch ( b )
>      {
> +    case 64: return n >> 6;
> +    case 32: return n >> 5;
> +    case 16: return n >> 4;

It doesn't sounds right to update this common function. What happen if
VGIC v2 is trying to use this value?

>      case 8: return n >> 3;
>      case 4: return n >> 2;
>      case 2: return n >> 1;
> @@ -89,6 +95,7 @@ void byte_write(uint32_t *reg, uint32_t var, int offset);
>  struct vgic_irq_rank *vgic_get_irqrank(struct vcpu *v, int rank);
>  extern void register_vgic_ops(struct vgic_ops *ops);
>  int vgic_v2_init(struct domain *d);
> +int vgic_v3_init(struct domain *d);
>  
>  #endif
>  
> 

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-15 11:17 ` [PATCH v3 13/16] xen/arm: Add support for GIC v3 vijay.kilari
  2014-04-15 20:43   ` Julien Grall
@ 2014-04-17  9:57   ` Julien Grall
  2014-04-17 11:00     ` Vijay Kilari
  2014-04-23 17:01   ` Ian Campbell
  2 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-17  9:57 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> +#define GICD_CTLR       (0x000)
> +#define GICD_TYPER      (0x004)
> +#define GICD_IIDR       (0x008)
> +#define GICD_STATUSR    (0x010)
> +#define GICD_SETSPI_NSR (0x040)
> +#define GICD_CLRSPI_NSR (0x048)
> +#define GICD_SETSPI_SR  (0x050)
> +#define GICD_CLRSPI_SR  (0x058)
> +#define GICD_IGROUPR    (0x080)
> +#define GICD_IGROUPRN   (0x0FC)
> +#define GICD_ISENABLER  (0x100)
> +#define GICD_ISENABLERN (0x17C)
> +#define GICD_ICENABLER  (0x180)
> +#define GICD_ICENABLERN (0x1fC)
> +#define GICD_ISPENDR    (0x200)
> +#define GICD_ISPENDRN   (0x27C)
> +#define GICD_ICPENDR    (0x280)
> +#define GICD_ICPENDRN   (0x2FC)
> +#define GICD_ISACTIVER  (0x300)
> +#define GICD_ISACTIVERN (0x37C)
> +#define GICD_ICACTIVER  (0x380)
> +#define GICD_ICACTIVERN (0x3FC)
> +#define GICD_IPRIORITYR (0x400)
> +#define GICD_IPRIORITYRN (0x7F8)
> +#define GICD_ICFGR      (0xC00)
> +#define GICD_ICFGRN     (0xCFC)
> +#define GICD_NSACR      (0xE00)
> +#define GICD_NSACRN     (0xEFC)
> +#define GICD_SGIR       (0xF00)
> +#define GICD_CPENDSGIR  (0xF10)
> +#define GICD_CPENDSGIRN (0xF1C)
> +#define GICD_SPENDSGIR  (0xF20)
> +#define GICD_SPENDSGIRN (0xF2C)
> +#define GICD_IROUTER    (0x6000)
> +#define GICD_IROUTERN   (0x7FF8)
> +#define GICD_PIDR0      (0xFFE0)
> +#define GICD_PIDR2      (0xFFE8)
> +#define GICD_PIDR7      (0xFFDC)

Most of this registers are the same as GICv2 except /4 right?

If so, it might be interesting to drop the /4 in the GICv2 so we will be
able to share most of the VGIC distr code.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-17  9:57   ` Julien Grall
@ 2014-04-17 11:00     ` Vijay Kilari
  2014-04-17 11:17       ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-04-17 11:00 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Thu, Apr 17, 2014 at 3:27 PM, Julien Grall <julien.grall@linaro.org> wrote:
> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
>> +#define GICD_CTLR       (0x000)
>> +#define GICD_TYPER      (0x004)
>> +#define GICD_IIDR       (0x008)
>> +#define GICD_STATUSR    (0x010)
>> +#define GICD_SETSPI_NSR (0x040)
>> +#define GICD_CLRSPI_NSR (0x048)
>> +#define GICD_SETSPI_SR  (0x050)
>> +#define GICD_CLRSPI_SR  (0x058)
>> +#define GICD_IGROUPR    (0x080)
>> +#define GICD_IGROUPRN   (0x0FC)
>> +#define GICD_ISENABLER  (0x100)
>> +#define GICD_ISENABLERN (0x17C)
>> +#define GICD_ICENABLER  (0x180)
>> +#define GICD_ICENABLERN (0x1fC)
>> +#define GICD_ISPENDR    (0x200)
>> +#define GICD_ISPENDRN   (0x27C)
>> +#define GICD_ICPENDR    (0x280)
>> +#define GICD_ICPENDRN   (0x2FC)
>> +#define GICD_ISACTIVER  (0x300)
>> +#define GICD_ISACTIVERN (0x37C)
>> +#define GICD_ICACTIVER  (0x380)
>> +#define GICD_ICACTIVERN (0x3FC)
>> +#define GICD_IPRIORITYR (0x400)
>> +#define GICD_IPRIORITYRN (0x7F8)
>> +#define GICD_ICFGR      (0xC00)
>> +#define GICD_ICFGRN     (0xCFC)
>> +#define GICD_NSACR      (0xE00)
>> +#define GICD_NSACRN     (0xEFC)
>> +#define GICD_SGIR       (0xF00)
>> +#define GICD_CPENDSGIR  (0xF10)
>> +#define GICD_CPENDSGIRN (0xF1C)
>> +#define GICD_SPENDSGIR  (0xF20)
>> +#define GICD_SPENDSGIRN (0xF2C)
>> +#define GICD_IROUTER    (0x6000)
>> +#define GICD_IROUTERN   (0x7FF8)
>> +#define GICD_PIDR0      (0xFFE0)
>> +#define GICD_PIDR2      (0xFFE8)
>> +#define GICD_PIDR7      (0xFFDC)
>
> Most of this registers are the same as GICv2 except /4 right?
>
> If so, it might be interesting to drop the /4 in the GICv2 so we will be
> able to share most of the VGIC distr code.
>
Few registers are common. There are additional registers in V3 like
IROUTER, PIDR.
The GICv2 defines are also used by gic-v2 driver as well which expects
register_address/4.
So changing this impacts existing GIC v2 driver as well.
The common code in vgic driver is only  read/write on GICD registers.
I could rename these registers into v2 & v3.

> Regards,
>
> --
> Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-17 11:00     ` Vijay Kilari
@ 2014-04-17 11:17       ` Julien Grall
  2014-04-17 14:54         ` Vijay Kilari
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-17 11:17 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 04/17/2014 12:00 PM, Vijay Kilari wrote:
> On Thu, Apr 17, 2014 at 3:27 PM, Julien Grall <julien.grall@linaro.org> wrote:
>> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
>>> +#define GICD_CTLR       (0x000)
>>> +#define GICD_TYPER      (0x004)
>>> +#define GICD_IIDR       (0x008)
>>> +#define GICD_STATUSR    (0x010)
>>> +#define GICD_SETSPI_NSR (0x040)
>>> +#define GICD_CLRSPI_NSR (0x048)
>>> +#define GICD_SETSPI_SR  (0x050)
>>> +#define GICD_CLRSPI_SR  (0x058)
>>> +#define GICD_IGROUPR    (0x080)
>>> +#define GICD_IGROUPRN   (0x0FC)
>>> +#define GICD_ISENABLER  (0x100)
>>> +#define GICD_ISENABLERN (0x17C)
>>> +#define GICD_ICENABLER  (0x180)
>>> +#define GICD_ICENABLERN (0x1fC)
>>> +#define GICD_ISPENDR    (0x200)
>>> +#define GICD_ISPENDRN   (0x27C)
>>> +#define GICD_ICPENDR    (0x280)
>>> +#define GICD_ICPENDRN   (0x2FC)
>>> +#define GICD_ISACTIVER  (0x300)
>>> +#define GICD_ISACTIVERN (0x37C)
>>> +#define GICD_ICACTIVER  (0x380)
>>> +#define GICD_ICACTIVERN (0x3FC)
>>> +#define GICD_IPRIORITYR (0x400)
>>> +#define GICD_IPRIORITYRN (0x7F8)
>>> +#define GICD_ICFGR      (0xC00)
>>> +#define GICD_ICFGRN     (0xCFC)
>>> +#define GICD_NSACR      (0xE00)
>>> +#define GICD_NSACRN     (0xEFC)
>>> +#define GICD_SGIR       (0xF00)
>>> +#define GICD_CPENDSGIR  (0xF10)
>>> +#define GICD_CPENDSGIRN (0xF1C)
>>> +#define GICD_SPENDSGIR  (0xF20)
>>> +#define GICD_SPENDSGIRN (0xF2C)
>>> +#define GICD_IROUTER    (0x6000)
>>> +#define GICD_IROUTERN   (0x7FF8)
>>> +#define GICD_PIDR0      (0xFFE0)
>>> +#define GICD_PIDR2      (0xFFE8)
>>> +#define GICD_PIDR7      (0xFFDC)
>>
>> Most of this registers are the same as GICv2 except /4 right?
>>
>> If so, it might be interesting to drop the /4 in the GICv2 so we will be
>> able to share most of the VGIC distr code.
>>
> Few registers are common. There are additional registers in V3 like
> IROUTER, PIDR.

You have some strange conception of few :). About 20 registers are
common with GICv2.

> The GICv2 defines are also used by gic-v2 driver as well which expects
> register_address/4.
> So changing this impacts existing GIC v2 driver as well.

I would prefer to modify GIC v2 driver rather than forking too much the
VGIC code. The change in GIC v2 is not so difficult...

It will save us lots of debugging time later. If we keep your solution,
if we find a bug in the vGICv2 distributor we have to check vGICv3
{re,distributor}. That would mean fixing the same bug in 3 places...

With my solution, you will be able to handle in common code the
registers valid on both configuration. Then calling vgic callbacks for
GICv3 specific registers.

It will also help to support vGICv2 on GICv3.

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-17 11:17       ` Julien Grall
@ 2014-04-17 14:54         ` Vijay Kilari
  2014-04-17 15:12           ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-04-17 14:54 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

Hi Julien,

On Thu, Apr 17, 2014 at 4:47 PM, Julien Grall <julien.grall@linaro.org> wrote:
> On 04/17/2014 12:00 PM, Vijay Kilari wrote:
>> On Thu, Apr 17, 2014 at 3:27 PM, Julien Grall <julien.grall@linaro.org> wrote:
>>> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
>>>> +#define GICD_CTLR       (0x000)
>>>> +#define GICD_TYPER      (0x004)
>>>> +#define GICD_IIDR       (0x008)
>>>> +#define GICD_STATUSR    (0x010)
>>>> +#define GICD_SETSPI_NSR (0x040)
>>>> +#define GICD_CLRSPI_NSR (0x048)
>>>> +#define GICD_SETSPI_SR  (0x050)
>>>> +#define GICD_CLRSPI_SR  (0x058)
>>>> +#define GICD_IGROUPR    (0x080)
>>>> +#define GICD_IGROUPRN   (0x0FC)
>>>> +#define GICD_ISENABLER  (0x100)
>>>> +#define GICD_ISENABLERN (0x17C)
>>>> +#define GICD_ICENABLER  (0x180)
>>>> +#define GICD_ICENABLERN (0x1fC)
>>>> +#define GICD_ISPENDR    (0x200)
>>>> +#define GICD_ISPENDRN   (0x27C)
>>>> +#define GICD_ICPENDR    (0x280)
>>>> +#define GICD_ICPENDRN   (0x2FC)
>>>> +#define GICD_ISACTIVER  (0x300)
>>>> +#define GICD_ISACTIVERN (0x37C)
>>>> +#define GICD_ICACTIVER  (0x380)
>>>> +#define GICD_ICACTIVERN (0x3FC)
>>>> +#define GICD_IPRIORITYR (0x400)
>>>> +#define GICD_IPRIORITYRN (0x7F8)
>>>> +#define GICD_ICFGR      (0xC00)
>>>> +#define GICD_ICFGRN     (0xCFC)
>>>> +#define GICD_NSACR      (0xE00)
>>>> +#define GICD_NSACRN     (0xEFC)
>>>> +#define GICD_SGIR       (0xF00)
>>>> +#define GICD_CPENDSGIR  (0xF10)
>>>> +#define GICD_CPENDSGIRN (0xF1C)
>>>> +#define GICD_SPENDSGIR  (0xF20)
>>>> +#define GICD_SPENDSGIRN (0xF2C)
>>>> +#define GICD_IROUTER    (0x6000)
>>>> +#define GICD_IROUTERN   (0x7FF8)
>>>> +#define GICD_PIDR0      (0xFFE0)
>>>> +#define GICD_PIDR2      (0xFFE8)
>>>> +#define GICD_PIDR7      (0xFFDC)
>>>
>>> Most of this registers are the same as GICv2 except /4 right?
>>>
>>> If so, it might be interesting to drop the /4 in the GICv2 so we will be
>>> able to share most of the VGIC distr code.
>>>
>> Few registers are common. There are additional registers in V3 like
>> IROUTER, PIDR.
>
> You have some strange conception of few :). About 20 registers are
> common with GICv2.
>
>> The GICv2 defines are also used by gic-v2 driver as well which expects
>> register_address/4.
>> So changing this impacts existing GIC v2 driver as well.
>
> I would prefer to modify GIC v2 driver rather than forking too much the
> VGIC code. The change in GIC v2 is not so difficult...

   Is it ok if we can get rid of usage fixmap in GICv2 driver to
access GICD/GICH/GICC regions
and use ioremap_nocache() similar to GICv3 driver?.

>
> It will save us lots of debugging time later. If we keep your solution,
> if we find a bug in the vGICv2 distributor we have to check vGICv3
> {re,distributor}. That would mean fixing the same bug in 3 places...
>
> With my solution, you will be able to handle in common code the
> registers valid on both configuration. Then calling vgic callbacks for
> GICv3 specific registers.
>
> It will also help to support vGICv2 on GICv3.
>
> --
> Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-17 14:54         ` Vijay Kilari
@ 2014-04-17 15:12           ` Julien Grall
  0 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-17 15:12 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 04/17/2014 03:54 PM, Vijay Kilari wrote:
>> I would prefer to modify GIC v2 driver rather than forking too much the
>> VGIC code. The change in GIC v2 is not so difficult...
> 
>    Is it ok if we can get rid of usage fixmap in GICv2 driver to
> access GICD/GICH/GICC regions
> and use ioremap_nocache() similar to GICv3 driver?.

I'm in favor of this solution. There is nearly no overhead compare to
the FIXMAP solution.

You will have to use ioremap_nocache and corresponding read/write helper.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information
  2014-04-15 11:17 ` [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information vijay.kilari
@ 2014-04-18 19:57   ` Julien Grall
  2014-04-24 10:46   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-18 19:57 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar

Hello Vijaya,

On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>
> Update GIC device tree node for DOM0 with GICv3
> information. GIC hw specfic device tree information
> is moved to respective GIC driver.
>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>   xen/arch/arm/domain_build.c |    9 +++------
>   xen/arch/arm/gic-v2.c       |    9 +++++++++
>   xen/arch/arm/gic-v3.c       |   33 +++++++++++++++++++++++++++++++++
>   xen/arch/arm/gic.c          |    5 +++++
>   xen/include/asm-arm/gic.h   |    4 ++++
>   5 files changed, 54 insertions(+), 6 deletions(-)
>
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index 5ca2f15..5ef08da 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -576,13 +576,10 @@ static int make_gic_node(const struct domain *d, void *fdt,
>           return -FDT_ERR_XEN(ENOMEM);
>   Hello
>       tmp = new_cells;
> -    DPRINT("  Set Distributor Base 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
> -           d->arch.vgic.dbase, d->arch.vgic.dbase + PAGE_SIZE - 1);
> -    dt_set_range(&tmp, node, d->arch.vgic.dbase, PAGE_SIZE);
>
> -    DPRINT("  Set Cpu Base 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
> -           d->arch.vgic.cbase, d->arch.vgic.cbase + (PAGE_SIZE * 2) - 1);
> -    dt_set_range(&tmp, node, d->arch.vgic.cbase, PAGE_SIZE * 2);
> +    res = gic_make_node(d, node, fdt, tmp);


This solution is buggy because tmp is allocated for only 2 ranges. GICv3 
can have more than 2 ranges.

Why do you give tmp rather than moving the creation of the property 
"reg" in each GIC driver?

I would also move all this function in gic_make_node for more clarity.

>   static const char * const gicv2_dt_compat[] __initconst =
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index 8625e0c..e27b094 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -30,6 +30,7 @@
>   #include <xen/softirq.h>
>   #include <xen/list.h>
>   #include <xen/device_tree.h>
> +#include <xen/libfdt/libfdt.h>
>   #include <xen/delay.h>
>   #include <asm/p2m.h>
>   #include <asm/domain.h>
> @@ -825,6 +826,37 @@ static unsigned int gicv3_read_vmcr_priority(void)
>               GICH_VMCR_PRIORITY_MASK);
>   }
>
> +int static gicv3_make_dt_node(const struct domain *d,

static should be before int.

> +              const struct dt_device_node *node, void *fdt, __be32 *cells)

With my previous remark, this callback should be:

gicv3_make_dt_node(const struct domain *d,
                    const struct dt_device_node *node, void *fdt)

And you allocate the number of cells in this function.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-04-15 11:17 ` [PATCH v3 16/16] xen/arm: add SGI handling for GICv3 vijay.kilari
@ 2014-04-18 20:20   ` Julien Grall
  2014-05-02 12:57     ` Vijay Kilari
  2014-04-24 10:57   ` Ian Campbell
  1 sibling, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-18 20:20 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar

Hello Vijaya,

On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>
> In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
> Handle the trap and inject SGI to vcpu.
>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>   xen/arch/arm/traps.c              |    9 +++++
>   xen/arch/arm/vgic-v3.c            |   79 +++++++++++++++++++++++++++++++++++++
>   xen/include/asm-arm/gic_v3_defs.h |   14 +++++++
>   xen/include/asm-arm/sysregs.h     |    2 +-
>   xen/include/asm-arm/vgic.h        |    1 +
>   5 files changed, 104 insertions(+), 1 deletion(-)
>
> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> index e0184b1..dc1f202 100644
> --- a/xen/arch/arm/traps.c
> +++ b/xen/arch/arm/traps.c
> @@ -40,6 +40,7 @@
>   #include "decode.h"
>   #include "vtimer.h"
>   #include <asm/gic.h>
> +#include <asm/vgic.h>
>
>   /* The base of the stack must always be double-word aligned, which means
>    * that both the kernel half of struct cpu_user_regs (which is pushed in
> @@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
>               domain_crash_synchronous();
>           }
>           break;
> +    case HSR_SYSREG_ICC_SGI1R_EL1:

Any reason to not trap ICC_SGI0R_EL1 and ICC_ASGI1R_EL1?

> +        if ( !vgic_emulate(regs, hsr) )
> +        {
> +            dprintk(XENLOG_ERR,
> +                    "failed emulation of 64-bit vgic sysreg access\n");
> +            domain_crash_synchronous();

So, you crash the domain if the SGI is not handled??? The GICv3 spec 
requests a specific behavior.

> +        }
> +        break;
>       default:
>           printk("%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n",
>                  sysreg.read ? "mrs" : "msr",

> +static int vgic_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
> +{
> +    struct vcpu *v = current;
> +    struct hsr_sysreg sysreg = hsr.sysreg;
> +    register_t *r = select_user_reg(regs, sysreg.reg);

Missing newline.

> +    switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
> +    {
> +    case HSR_SYSREG_ICC_SGI1R_EL1:
> +        /* WO */
> +        if ( !sysreg.read )
> +            return vgic_to_sgi(v, *r);
> +        else
> +        {
> +            gdprintk(XENLOG_WARNING, "Reading SGI1R_EL1 - WO register\n");
> +            return 0;
> +        }
> +    default:
> +        return 0;
> +    }
> +}
> +
> +int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)

You should extend the gic ops rather than by pass the GIC common code.

> +{
> +    switch ( hsr.ec )
> +    {
> +    case HSR_EC_SYSREG:
> +        return vgic_emulate_sysreg(regs, hsr);
> +    default:
> +        return 0;
> +    }
> +}
> +

[..]

>   #endif /* __ASM_ARM_GIC_V3_DEFS_H__ */
>
>   /*
> diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h
> index 0cee0e9..18e5a45 100644
> --- a/xen/include/asm-arm/sysregs.h
> +++ b/xen/include/asm-arm/sysregs.h
> @@ -56,7 +56,7 @@
>   #define HSR_SYSREG_CNTP_CTL_EL0   HSR_SYSREG(3,3,c14,c2,1)
>   #define HSR_SYSREG_CNTP_TVAL_EL0  HSR_SYSREG(3,3,c14,c2,0)
>
> -
> +#define HSR_SYSREG_ICC_SGI1R_EL1  HSR_SYSREG(3,0,c12,c11,5)

Newline here please.

>   #endif
>
>   #endif

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder
  2014-04-15 11:17 ` [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder vijay.kilari
  2014-04-15 16:36   ` Julien Grall
@ 2014-04-23 14:16   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:16 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> io.h is local to arch/arm folder. move this file as mmio.h
> file to include/asm-arm folder as it might be
> required for inclusion in other header files in future.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/io.h          |   57 --------------------------------------------
> [...]
>  xen/include/asm-arm/mmio.h |   57 ++++++++++++++++++++++++++++++++++++++++++++

Please can you use the -M option to git format-patch/send-email which
would then show this as a rename.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 02/16] xen/arm: make mmio handlers domain specific
  2014-04-15 17:07   ` Julien Grall
@ 2014-04-23 14:27     ` Ian Campbell
  0 siblings, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:27 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 18:07 +0100, Julien Grall wrote:

> > +    for ( i = 0; i < mmio_handle->num_entries; i++ )
> > +    {
> > +        if ( (info->gpa >= mmio_handle->mmio_handlers[i]->addr) &&
> > +              info->gpa < (mmio_handle->mmio_handlers[i]->addr + mmio_handle->mmio_handlers[i]->size) )
> 
> The coding style request line length below 80 characters.

A temporary variable to hold &mmio_handle->mmio_handlers[i] inside the
loop body would make this a lot clearer IMHO.

I'd be tempted to rename the existing mmio_handle to mmio_handlers.

> 
> >              return info->dabt.write ?
> > -                mmio_handlers[i]->write_handler(v, info) :
> > -                mmio_handlers[i]->read_handler(v, info);
> > -
> > +                mmio_handle->mmio_handlers[i]->write_handler(v, info) :
> > +                mmio_handle->mmio_handlers[i]->read_handler(v, info);
> > +    }
> 
> Newline here for clarity.
> 
> >      return 0;
> >  }
> > +
> > +void register_mmio_handler(struct domain *d, struct mmio_handler * handle)
> > +{
> > +    struct io_handler *handler = &d->arch.io_handlers;
> > +
> > +    BUG_ON(handler->num_entries >= MAX_IO_HANDLER);
> > +
> > +    spin_lock(&handler->lock);
> > +    handler->mmio_handlers[handler->num_entries] = handle;
> > +    handler->num_entries++;
> 
> If you plan to use spinlock only when a new entry is added, you need a
> dsb(is) before increment num_entries. Smth like
> 
> handler->mmio_handlers[handler->num_entries] = handle;
> dbs(sy);

I don't think this needs to be sy, ish should be enough, possibly even
ishst. I expect you'd also need a corresponding read barrier in
handle_mmio. I suspect you might need to do there:
	num = mmio_handle->num_entries
	barrier
	for (... i < num ;...)

(this wouldn't handle deregistration, which doesn't matter here but
might in the future?)

> > +   return 0;
> > +}
> > +
> >  /*
> >   * Local variables:
> >   * mode: C
> > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> > index 9c404fe..d36058a 100644
> > --- a/xen/arch/arm/vgic.c
> > +++ b/xen/arch/arm/vgic.c
> > @@ -35,6 +35,8 @@
> >  /* Number of ranks of interrupt registers for a domain */
> >  #define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
> >  
> > +static struct mmio_handler vgic_distr_mmio_handler;
> > +
> >  /*
> >   * Rank containing GICD_<FOO><n> for GICD_<FOO> with
> >   * <b>-bits-per-interrupt
> > @@ -98,6 +100,10 @@ int domain_vgic_init(struct domain *d)
> >      }
> >      for (i=0; i<DOMAIN_NR_RANKS(d); i++)
> >          spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
> > +
> > +    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
> > +    vgic_distr_mmio_handler.size = PAGE_SIZE;
> > +    register_mmio_handler(d, &vgic_distr_mmio_handler);
> 
> This is wrong. register_mmio_handler is directly copying the MMIO
> handler. So updating addr will breaks other domains as the vgic.dbase
> may differ.

Absolutely!

> I think my solution on V1 was correct. I.e smth like
> 
> register_mmio_handler(d, &vgic_distr_mmio_handler, address, size);

Or make iohandlers be an array of actual struct mmio_handler rather than
pointers to them and copy the input of register_mmio_handler (which is
what x86 does)

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 03/16] xen/arm: make sgi handling generic
  2014-04-15 17:51   ` Julien Grall
  2014-04-15 17:57     ` Julien Grall
@ 2014-04-23 14:31     ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:31 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 18:51 +0100, Julien Grall wrote:
> > +    default:
> > +         gdprintk(XENLOG_WARNING, "Wrong sgi irq mode for sgi %x\n", sgi);
> 
> You can't use gdprintk here as the function may not be used by guest.
> 
> You should replace by dprintk(...). Even better a BUG_ON as this should
> be never reached.

Yes, BUG_ON please.

> >  void smp_send_state_dump(unsigned int cpu)
> > diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> > index 5d8f7f1..d03b490 100644
> > --- a/xen/include/asm-arm/gic.h
> > +++ b/xen/include/asm-arm/gic.h
> > @@ -50,6 +50,10 @@
> >  #define GICD_SPENDSGIRN (0xF2C/4)
> >  #define GICD_ICPIDR2    (0xFE8/4)
> >  
> > +#define SGI_TARGET_LIST    0
> > +#define SGI_TARGET_OTHERS  1
> > +#define SGI_TARGET_SELF    2
> > +
[..]
> I would also use an enum as we know it's bound.

Yes, please.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call
  2014-04-15 11:17 ` [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call vijay.kilari
  2014-04-15 17:52   ` Julien Grall
@ 2014-04-23 14:32   ` Ian Campbell
  2014-04-25  9:28     ` Vijay Kilari
  1 sibling, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:32 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> othercpu parameter in do_sgi is unused
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

I take it gic v3 doesn't tell us who sent an SGI?

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 05/16] xen/arm: move gic definitions to seperate file
  2014-04-15 11:17 ` [PATCH v3 05/16] xen/arm: move gic definitions to seperate file vijay.kilari
@ 2014-04-23 14:34   ` Ian Campbell
  0 siblings, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:34 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Move gic v2 register definitions to separate file
> so that gic.h will hold only common definitions
> and helps to define gic v3 definitions.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

(I did think you were going to try and share some of the code which used
these though)

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure
  2014-04-15 11:17 ` [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure vijay.kilari
@ 2014-04-23 14:35   ` Ian Campbell
  2014-05-12 13:49   ` Julien Grall
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:35 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> spinlock is used across generic and GIC low level
> functions. Move this lock out of gic data.
> This helps to separate generic and low level functions
> later.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>

Acked-by: Ian Campbell <ian.campbell@citrix.com>

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-15 11:17 ` [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality vijay.kilari
  2014-04-15 18:35   ` Julien Grall
  2014-04-15 21:00   ` Julien Grall
@ 2014-04-23 14:52   ` Ian Campbell
  2014-04-28 14:41     ` Vijay Kilari
  2 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:52 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> GIC driver contains both generic and hardware specific low
> level functionality in gic.c file.
> 
> With this patch, low level functionality is moved to separate
> file gic-v2.c and generic code is kept in gic.c file
> 
> Callbacks are registered by low level driver with generic driver
> and are called whereever required.
> 
> The locking mechanism is now kept in generic code as is and
> hence it is upto generic driver to take proper locks before
> calling low level driver callbacks.

Please can you document this no a per hook basis in the definition of
struct gic_hw_operations.

> This helps to separate generic and hardware functionality

> +static struct gic_hw_operations gic_ops;

Please order the file:
	callbacks
	gic_hw_ops struct
	initialisation functions

Then you can avoid the forward reference and hopefully make things
const.

> +static struct dt_irq * gicv2_maintenance_irq(void)
> +{
> +    return &gic.maintenance;

How much does the generic maintenance interrupt handling do? Seems like
just routing it and requesting it, in which case I wonder if we
shouldn't just push all the MI stuff down into the specific drivers.
What do you think?

> +static void gicv2_read_lr(int lr, struct gic_lr *lr_reg)
> +{
> +    uint32_t lrv;
> +
> +    lrv = GICH[GICH_LR + lr];
> +    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
> +    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK;
> +    lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK;
> +    lr_reg->state    = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
> +    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;
> +    lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;

Please either line up the = or don't, not a mixture.

> +static struct gic_hw_operations gic_ops = {

Can be const I think?

> +    .secondary_init      = gicv2_secondary_cpu_init,
> +    .get_maintenance_irq = gicv2_maintenance_irq,
> +    .save_state          = gicv2_save_state,
> +    .restore_state       = gicv2_restore_state,
> +    .dump_state          = gicv2_dump_state,
> +    .gicv_setup          = gicv_v2_init,
> +    .gic_irq_ops         = &irq_ops,
> +    .deactivate_irq      = gicv2_dir_irq,
> +    .ack_irq             = gicv2_ack_irq,
> +    .set_irq_property    = gicv2_set_irq_properties,
> +    .send_sgi            = gicv2_send_sgi,
> +    .disable_interface   = gicv2_disable_interface,
> +    .update_lr           = gicv2_update_lr,
> +    .update_hcr_status   = gicv2_hcr_status,
> +    .clear_lr            = gicv2_clear_lr,
> +    .read_lr             = gicv2_read_lr,
> +    .write_lr            = gicv2_write_lr,
> +    .read_vmcr_priority  = gicv2_read_vmcr_priority,
> +};
> +
> +/*
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index eba41ee..2387e38 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -43,12 +43,41 @@
>  #define SGI_TARGET_OTHERS  1
>  #define SGI_TARGET_SELF    2
>  
> +#define GICH_LR_PENDING    1
> +#define GICH_LR_ACTIVE     2
> +
> +#define GICH_HCR_EN       (1 << 0)
> +#define GICH_HCR_UIE      (1 << 1)
> +#define GICH_HCR_LRENPIE  (1 << 2)
> +#define GICH_HCR_NPIE     (1 << 3)
> +#define GICH_HCR_VGRP0EIE (1 << 4)
> +#define GICH_HCR_VGRP0DIE (1 << 5)
> +#define GICH_HCR_VGRP1EIE (1 << 6)
> +#define GICH_HCR_VGRP1DIE (1 << 7)

Didn't you just move all these out of this file in a previous patch?
Please don't do that.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-15 18:35   ` Julien Grall
@ 2014-04-23 14:55     ` Ian Campbell
  2014-04-23 15:01       ` Julien Grall
  2014-04-28 11:48     ` Vijay Kilari
  1 sibling, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:55 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 19:35 +0100, Julien Grall wrote:
> > diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> > index eba41ee..2387e38 100644
> > --- a/xen/include/asm-arm/gic.h
> > +++ b/xen/include/asm-arm/gic.h
> > @@ -43,12 +43,41 @@
> >  #define SGI_TARGET_OTHERS  1
> >  #define SGI_TARGET_SELF    2
> >  
> > +#define GICH_LR_PENDING    1
> > +#define GICH_LR_ACTIVE     2
> > +
> 
> Prefixing by GICH_ is confusing. I though we were using it for to set
> the value in the hardware. Can you rename it?

This is code motion of an existing definition, definitely please don't
rename it at the same time.

But anyway, these are bits relating to the v2 GICH_LR register, which is
the same on v3 as it happens. So I think the names are fine.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver
  2014-04-15 18:41   ` Julien Grall
@ 2014-04-23 14:57     ` Ian Campbell
  0 siblings, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:57 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 19:41 +0100, Julien Grall wrote:
> Hello Vijaya,
> 
> Thank you for your patch.
> 
> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> > index 999bbdd..be1b084 100644
> > --- a/xen/include/asm-arm/domain.h
> > +++ b/xen/include/asm-arm/domain.h
> > @@ -8,6 +8,7 @@
> >  #include <asm/p2m.h>
> >  #include <asm/vfp.h>
> >  #include <asm/mmio.h>
> > +#include <asm/gic.h>
> >  #include <public/hvm/params.h>
> >  #include <xen/serial.h>
> >  
> > @@ -260,8 +261,7 @@ struct arch_vcpu
> >      uint32_t csselr;
> >      register_t vmpidr;
> >  
> > -    uint32_t gic_hcr, gic_vmcr, gic_apr;
> > -    uint32_t gic_lr[64];
> 
> I would add a comment such as "GIC state" here.

If that isn't obvious from the name of the union then a comment isn't
going to help.

> > +    union gic_state_data gic;
> >      uint64_t event_mask;
> >      uint64_t lr_mask;
> 
> [..]
> 
> > +struct gic_v2 {
> > +    uint32_t hcr, vmcr;
> > +    uint32_t apr;
> > +    uint32_t lr[64];
> > +};
> > +
> 
> Even if with the name you know it's GICv2. Can you document quickly the
> structure?

Lets not ask him to continually shave yaks as part of this. These were
clear enough before and they are clear enough now.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver
  2014-04-15 11:17 ` [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver vijay.kilari
  2014-04-15 18:41   ` Julien Grall
@ 2014-04-23 14:58   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 14:58 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> GIC specific context data structure that saves and restores
> GIC  registers are moved to gic.h from domain.h
> The structure is converted to union so that we can
> add version specific structure to this union for
> later GIC versions.

Ack to the union bit, can you expand on why it had to move from domain.h
to gic.h though? Most other similar state structs remain in domian.h.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-23 14:55     ` Ian Campbell
@ 2014-04-23 15:01       ` Julien Grall
  2014-04-23 16:47         ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-23 15:01 UTC (permalink / raw)
  To: Ian Campbell
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/23/2014 03:55 PM, Ian Campbell wrote:
> On Tue, 2014-04-15 at 19:35 +0100, Julien Grall wrote:
>>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>>> index eba41ee..2387e38 100644
>>> --- a/xen/include/asm-arm/gic.h
>>> +++ b/xen/include/asm-arm/gic.h
>>> @@ -43,12 +43,41 @@
>>>  #define SGI_TARGET_OTHERS  1
>>>  #define SGI_TARGET_SELF    2
>>>  
>>> +#define GICH_LR_PENDING    1
>>> +#define GICH_LR_ACTIVE     2
>>> +
>>
>> Prefixing by GICH_ is confusing. I though we were using it for to set
>> the value in the hardware. Can you rename it?
> 
> This is code motion of an existing definition, definitely please don't
> rename it at the same time.
> 
> But anyway, these are bits relating to the v2 GICH_LR register, which is
> the same on v3 as it happens. So I think the names are fine.

Reading again the code, you are right. I was confused then of the value
and the position at the same time.

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 09/16] xen/arm: use device api to detect GIC version
  2014-04-15 11:17 ` [PATCH v3 09/16] xen/arm: use device api to detect GIC version vijay.kilari
  2014-04-15 18:49   ` Julien Grall
@ 2014-04-23 15:01   ` Ian Campbell
  2014-04-29  7:07     ` Vijay Kilari
  1 sibling, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 15:01 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> +static const char * const gicv2_dt_compat[] __initconst =
> +{
> +    "arm,cortex-a15-gic",
> +    "arm,cortex-a9-gic",

This is DT_MATCH_GIC. Please keep using it. Perhaps you will want to
rename it to DT_MATCH_GICV2.

> [...]

> +
> +        rc = device_init(node, DEVICE_GIC, NULL);
> +        if ( !rc )
> +        {
> +            num_gics++;

Please can you add a comment to the affect that we only support one GIC
right now.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 11/16] xen/arm: move vgic defines to vgic header file
  2014-04-16 17:01   ` Julien Grall
@ 2014-04-23 15:07     ` Ian Campbell
  2014-04-23 15:11       ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 15:07 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Wed, 2014-04-16 at 18:01 +0100, Julien Grall wrote:
> Hello Vijaya,
> 
> Thank you for the patch.
> 
> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> > From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> > 
> > gic.h contains defines of vgic. Move these to vgic
> > header file. Also move inline functions and defines
> > in vgic.c to vgic.h
> 
> Can you explain in the commit message, why you need to move theses
> functions in the header?

Yeah, many of them look like they will really belong in either vgic.c or
vgic-v2.c. Which ones are actually used by both the generic and specific
code?

> > +static inline int is_vcpu_running(struct domain *d, int vcpuid)
> 
> 
> The name of the 2 functions and 1 define are too generic. It was fine
> internally but not to be exported.

is_vcpu_running is fine IMHO.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 11/16] xen/arm: move vgic defines to vgic header file
  2014-04-23 15:07     ` Ian Campbell
@ 2014-04-23 15:11       ` Julien Grall
  2014-04-23 15:15         ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-23 15:11 UTC (permalink / raw)
  To: Ian Campbell
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/23/2014 04:07 PM, Ian Campbell wrote:
> On Wed, 2014-04-16 at 18:01 +0100, Julien Grall wrote:
>> Hello Vijaya,
>>
>> Thank you for the patch.
>>
>> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>
>>> gic.h contains defines of vgic. Move these to vgic
>>> header file. Also move inline functions and defines
>>> in vgic.c to vgic.h
>>
>> Can you explain in the commit message, why you need to move theses
>> functions in the header?
> 
> Yeah, many of them look like they will really belong in either vgic.c or
> vgic-v2.c. Which ones are actually used by both the generic and specific
> code?
> 
>>> +static inline int is_vcpu_running(struct domain *d, int vcpuid)
>>
>>
>> The name of the 2 functions and 1 define are too generic. It was fine
>> internally but not to be exported.
> 
> is_vcpu_running is fine IMHO.

With this name, I don't think this function should belong to vgic.h

Can it be a common code function (i.e ARM & x86)? Maybe sched.h?

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver
  2014-04-15 11:17 ` [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver vijay.kilari
  2014-04-15 20:05   ` Julien Grall
@ 2014-04-23 15:12   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 15:12 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Existing vGIC driver has both generic code and hw specific
> code. Segregate vGIC low level driver into vgic-v2.c and
> keep generic code in existing vgic.c file
> 
> some static generic functions in vgic.c is made as non-static
> so that these generic functions can be used in vGIC v2 driver.
> 
> vGIC v2 driver registers required callbacks to generic vGIC
> driver. This helps to plug in next version of vGIC drivers
> like vGIC v3

Please can you clarify that the intention here is that all domains use
the same version of vgic as the physical gic. Otherwise I'm going to ask
why these callbacks aren't domain specific.

> +struct vgic_ops {
> +    int (*vgic_vcpu_init)(struct vcpu *v);
> +    int (*vgic_domain_init)(struct domain *d);

The vgic prefix here is unnecessary.

> +    int (*read_priority)(struct vcpu *v, int irq);

get_irq_priority would be a better name I think.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 11/16] xen/arm: move vgic defines to vgic header file
  2014-04-23 15:11       ` Julien Grall
@ 2014-04-23 15:15         ` Ian Campbell
  0 siblings, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 15:15 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Wed, 2014-04-23 at 16:11 +0100, Julien Grall wrote:
> On 04/23/2014 04:07 PM, Ian Campbell wrote:
> > On Wed, 2014-04-16 at 18:01 +0100, Julien Grall wrote:
> >> Hello Vijaya,
> >>
> >> Thank you for the patch.
> >>
> >> On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> >>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> >>>
> >>> gic.h contains defines of vgic. Move these to vgic
> >>> header file. Also move inline functions and defines
> >>> in vgic.c to vgic.h
> >>
> >> Can you explain in the commit message, why you need to move theses
> >> functions in the header?
> > 
> > Yeah, many of them look like they will really belong in either vgic.c or
> > vgic-v2.c. Which ones are actually used by both the generic and specific
> > code?
> > 
> >>> +static inline int is_vcpu_running(struct domain *d, int vcpuid)
> >>
> >>
> >> The name of the 2 functions and 1 define are too generic. It was fine
> >> internally but not to be exported.
> > 
> > is_vcpu_running is fine IMHO.
> 
> With this name, I don't think this function should belong to vgic.h
> 
> Can it be a common code function (i.e ARM & x86)? Maybe sched.h?

I haven't looked at the implementation to see if it makes sense for x86,
but if so then sched.h is fine. Otherwise some asm header would be fine
too.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-23 15:01       ` Julien Grall
@ 2014-04-23 16:47         ` Julien Grall
  2014-04-23 17:03           ` Ian Campbell
  2014-04-24  8:19           ` Ian Campbell
  0 siblings, 2 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-23 16:47 UTC (permalink / raw)
  To: Ian Campbell, vijay.kilari
  Cc: Prasun.Kapoor, vijaya.kumar, xen-devel, stefano.stabellini,
	stefano.stabellini

On 04/23/2014 04:01 PM, Julien Grall wrote:
> On 04/23/2014 03:55 PM, Ian Campbell wrote:
>> On Tue, 2014-04-15 at 19:35 +0100, Julien Grall wrote:
>>>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>>>> index eba41ee..2387e38 100644
>>>> --- a/xen/include/asm-arm/gic.h
>>>> +++ b/xen/include/asm-arm/gic.h
>>>> @@ -43,12 +43,41 @@
>>>>  #define SGI_TARGET_OTHERS  1
>>>>  #define SGI_TARGET_SELF    2
>>>>  
>>>> +#define GICH_LR_PENDING    1
>>>> +#define GICH_LR_ACTIVE     2
>>>> +
>>>
>>> Prefixing by GICH_ is confusing. I though we were using it for to set
>>> the value in the hardware. Can you rename it?
>>
>> This is code motion of an existing definition, definitely please don't
>> rename it at the same time.
>>
>> But anyway, these are bits relating to the v2 GICH_LR register, which is
>> the same on v3 as it happens. So I think the names are fine.
> 
> Reading again the code, you are right. I was confused then of the value
> and the position at the same time.

After thinking it would be nice to keep the shift in it smth like:

#define GICH_LR_PENDING (1 << 0)
#define GICH_LR_ACTION  (1 << 1)

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-15 11:17 ` [PATCH v3 13/16] xen/arm: Add support for GIC v3 vijay.kilari
  2014-04-15 20:43   ` Julien Grall
  2014-04-17  9:57   ` Julien Grall
@ 2014-04-23 17:01   ` Ian Campbell
  2014-04-23 17:24     ` Julien Grall
                       ` (2 more replies)
  2 siblings, 3 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 17:01 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:

> +#include <xen/config.h>
> +#include <xen/lib.h>
> +#include <xen/init.h>
> +#include <xen/cpu.h>
> +#include <xen/mm.h>
> +#include <xen/irq.h>
> +#include <xen/sched.h>
> +#include <xen/errno.h>
> +#include <xen/serial.h>
> +#include <xen/softirq.h>
> +#include <xen/list.h>
> +#include <xen/device_tree.h>
> +#include <xen/delay.h>
> +#include <asm/p2m.h>
> +#include <asm/domain.h>
> +#include <asm/platform.h>

Do you really need all of these? serial.h for example?

> +
> +#include <asm/gic_v3_defs.h>
> +#include <asm/gic.h>
> +#include <asm/io.h>
> +#include <asm/device.h>
> +
> +static struct gic_hw_operations gic_ops;
> +
> +struct rdist_region {
> +    paddr_t rdist_base;
> +    paddr_t rdist_base_size;
> +    void __iomem *map_rdist_base;

"base", "size" and "map" would be adequate field names I think.

> +};
> +
> +/* Global state */
> +static struct {
> +    paddr_t dbase;            /* Address of distributor registers */
> +    paddr_t dbase_size;
> +    void __iomem *map_dbase;  /* Mapped address of distributor registers */
> +    struct rdist_region *rdist_regions;
> +    u32  rdist_stride;
> +    unsigned int rdist_count; /* Number of rdist regions count */
> +    unsigned int lines;       /* Number of interrupts (SPIs + PPIs + SGIs) */
> +    struct dt_irq maintenance;
> +}gic;
> +
> +/* per-cpu re-distributor base */
> +static DEFINE_PER_CPU(void __iomem*, rbase);

Does this end up containing one of the gic.rdist_regions[i].map entries?
Any reason to duplicate this in that map field as well? Can't each
processor map it as it is initialised and store it here directly?

I suppose we have plenty of ioremap space on v8, so nr_cpus*2*64k isn't
too bad and there's no need to go for per-pcpu pagetables with a
dedicated virtual address region for the redistributors.

> +static u64 gich_read_lr(int lr)
> +{
> +    switch ( lr )
> +    {
> +    case 0: /* ICH_LRn is 64 bit */
> +        return READ_SYSREG(ICH_LR0_EL2);
> +        break;

All of these breaks are redundant. I think you could get away with
	case N: return READ_(..._LRn_EL2);
for brevity even.
> +
> +/* Wait for completion of a distributor change */
> +static void gicv3_do_wait_for_rwp(void __iomem *base)
> +{
> +    u32 val;
> +    u32 count = 1000000;
> +
> +    do {
> +        val = readl_relaxed(base + GICD_CTLR);
> +        if ( !(val & GICD_CTLR_RWP) )
> +           break;
> +        cpu_relax();
> +        udelay(1);

Ick. Is there no event when rwp changes, so we could do wfe here?

Could we at least use NOW() and MILLISECS() to construct a delay of a
known length?

> +    } while ( count-- );
> +
> +    if ( !count )
> +        dprintk(XENLOG_WARNING, "RWP timeout\n");

Shouldn't we panic here?

And if we are going to panic, we might as well wait forever? (Perhaps
with a warning after some number of iterations.

> +static unsigned int gicv3_mask_cpu(const cpumask_t *cpumask)

this returns an arbitrary cpu from cpumask? Can we name it as such
please.

The v2 equivalent returns a value suitable for GICD_ITARGETSR, which
might contain multiple valid target CPUs. Does GICD_IROUTER not have the
same property?

> +{
> +    unsigned int cpu;
> +    cpumask_t possible_mask;
> +
> +    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
> +    cpu = cpumask_any(&possible_mask);
> +    return cpu;
> +}
> +
> +static void write_aprn_regs(union gic_state_data *d)

Given the usage I think this should be restore_aprn_regs.

> +{
> +    ASSERT((nr_priorities > 4 && nr_priorities < 8));
> +    /* Write APRn register based on number of priorities
> +       plaform has implemented */

"platform"

> +    switch ( nr_priorities )
> +    {
> +    case 7:
> +        WRITE_SYSREG32(d->v3.apr0[2], ICH_AP0R2_EL2);
> +        WRITE_SYSREG32(d->v3.apr1[2], ICH_AP1R2_EL2);
> +        /* Fall through */
> +    case 6:
> +        WRITE_SYSREG32(d->v3.apr0[1], ICH_AP0R1_EL2);
> +        WRITE_SYSREG32(d->v3.apr1[1], ICH_AP1R1_EL2);
> +        /* Fall through */
> +    case 5:
> +        WRITE_SYSREG32(d->v3.apr0[0], ICH_AP0R0_EL2);
> +        WRITE_SYSREG32(d->v3.apr1[0], ICH_AP1R0_EL2);
> +        break;
> +    default:

BUG_ON?

> +        break;
> +    }
> +}
> +
> +static void read_aprn_regs(union gic_state_data *d)

The same three comments as write_* apply here too.

> +static void gicv3_save_state(struct vcpu *v)
> +{
> +    int i;
> +
> +    /* No need for spinlocks here because interrupts are disabled around
> +     * this call and it only accesses struct vcpu fields that cannot be
> +     * accessed simultaneously by another pCPU.
> +     */
> +    for ( i = 0; i < nr_lrs; i++)
> +        v->arch.gic.v3.lr[i] = gich_read_lr(i);
> +
> +    read_aprn_regs(&v->arch.gic); 
> +    v->arch.gic.v3.vmcr = READ_SYSREG32(ICH_VMCR_EL2);
> +}
> +
> +static void gicv3_restore_state(struct vcpu *v)
> +{
> +    int i;
> +
> +    for ( i = 0; i < nr_lrs; i++)
> +        gich_write_lr(i, v->arch.gic.v3.lr[i]);

I wonder if the compiler could do a better job of this using the same
switch and fallthrough method you used for aprn regs?

> +
> +    write_aprn_regs(&v->arch.gic);
> +
> +    WRITE_SYSREG32(v->arch.gic.v3.vmcr, ICH_VMCR_EL2);
> +}

> +static void gicv3_enable_irq(struct irq_desc *irqd)
> +{
> +    int irq = irqd->irq;
> +    uint32_t enabler;
> +
> +    /* Enable routing */
> +    if ( irq < NR_GIC_LOCAL_IRQS )
> +    {
> +        enabler = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
> +        enabler |= (1u << irq);
> +        writel_relaxed(enabler, GICD_RDIST_SGI_BASE + GICR_ISENABLER0);

I don't think the enable registers need read-modufy-wirte, do they? You
just write the bit you want to enable, like you do with the clear
ICENABLER registers.

> +static u64 gic_mpidr_to_affinity(u64 mpidr)
> +{
> +    u64 aff;
> +    /* Make sure we don't broadcast the interrupt */
> +     aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |

Indentation here is squiffy.

> +            MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
> +            MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
> +            MPIDR_AFFINITY_LEVEL(mpidr, 0)) & ~GICD_IROUTER_SPI_MODE_ANY;
> +    return aff;
> +}
> +
> +/*
> + * - needs to be called with gic.lock held
> + * - needs to be called with a valid cpu_mask, ie each cpu in the mask has
> + * already called gic_cpu_init
> + */
> +static void gicv3_set_irq_property(unsigned int irq, bool_t level,
> +                                   const cpumask_t *cpu_mask,
> +                                   unsigned int priority)
> +{
> +    uint32_t cfg, edgebit;
> +    u64 affinity;
> +    unsigned int cpu = gicv3_mask_cpu(cpu_mask);
> +
> +
> +    /* Set edge / level */
> +    if ( irq < NR_GIC_SGI )
> +        /* SGI's are always edge-triggered not need to call GICD_ICFGR0 */

s/not/no/ I think.

But then given the comment you do anyway?

> +        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR0);
> +    else if ( irq < NR_GIC_LOCAL_IRQS )
> +        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR1);
> +    else
> +        cfg = readl_relaxed(GICD + GICD_ICFGR + (irq / 16) * 4);
> +
> +    edgebit = 2u << (2 * (irq % 16));
> +    if ( level )
> +        cfg &= ~edgebit;
> +    else
> +        cfg |= edgebit;
> +
> +    if ( irq < NR_GIC_SGI )
> +       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR0);
> +    else if ( irq < NR_GIC_LOCAL_IRQS )
> +       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR1);
> +    else
> +       writel_relaxed(cfg, GICD + GICD_ICFGR + (irq / 16) * 4);
> +
> +    affinity = gic_mpidr_to_affinity(cpu_logical_map(cpu));
> +    if ( irq >= NR_GIC_LOCAL_IRQS )
> +        writeq_relaxed(affinity, (GICD + GICD_IROUTER + irq * 8));
> +
> +    /* Set priority */
> +    if ( irq < NR_GIC_LOCAL_IRQS )
> +    {

The {}s here aren't needed.

> +        writeb_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + irq);
> +    }
> +    else 
> +    {
> +        writeb_relaxed(priority, GICD + GICD_IPRIORITYR + irq);
> +    }
> +}
> +
> +static void gicv3_enable_redist(void)
> +{
> +    u32 val;
> +    /* Wait for 1s */
> +    u32 count = 1000000;

NOW() + MILLISECS(...) based again?

> +
> +    /* Wake up this CPU redistributor */
> +    val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
> +    val &= ~GICR_WAKER_ProcessorSleep;
> +    writel_relaxed(val, GICD_RDIST_BASE + GICR_WAKER);
> +
> +    do {
> +         val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
> +         if ( !(val & GICR_WAKER_ChildrenAsleep) )
> +           break;
> +         cpu_relax();
> +         udelay(1);
> +    } while ( count-- );
> +
> +    if ( !count )
> +        gdprintk(XENLOG_WARNING, "Redist enable RWP timeout\n");
> +}
> +
> +static int __init gicv3_populate_rdist(void)
> +{
> +    u64 mpidr = cpu_logical_map(smp_processor_id());
> +    u64 typer;
> +    uint32_t aff;

You have an interesting mix of u64 and uint32_t. Please stick to one or
the other, preferable uintXX_t.

> +    int i;
> +    uint32_t reg;
> +
> +    aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
> +           MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
> +           MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
> +           MPIDR_AFFINITY_LEVEL(mpidr, 0));

Is this not gic_mpidr_to_affinity?

> +
> +    for ( i = 0; i < gic.rdist_count; i++ )
> +    {
> +        void __iomem *ptr = gic.rdist_regions[i].map_rdist_base;
> +
> +        reg = readl_relaxed(ptr + GICR_PIDR2);
> +        if ( (reg & GICR_PIDR2_ARCH_MASK) != GICR_PIDR2_GICV3 ) {
> +            dprintk(XENLOG_WARNING, "No redistributor present @%"PRIpaddr"\n",
> +                   (u64)ptr);

What is with this cast? What is wrong with %p?

But in fact I think the virtual address is pretty meaningless. You
should print the associated physical address.

> +            break;
> +        }
> +
> +        do {
> +            typer = readq_relaxed(ptr + GICR_TYPER);
> +            if ( (typer >> 32) == aff )
> +            {
> +                this_cpu(rbase) = ptr;
> +                printk("CPU%d: Found redistributor in region %d\n",
> +                           smp_processor_id(), i);

Print the paddr of the distributor too?

> +                return 0;

So basically we only know the number of redistributors from device tree
and not the mapping from RDIST to CPU, so we have to try every one?

Do you have a reference to the GIC v3 Device Tree bindings? I don't see
them in linux/Documentation/devicetree/bindings/.

> +            }
> +            if ( gic.rdist_stride ) {
> +                ptr += gic.rdist_stride;
> +            } else {
> +                ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
> +                if ( typer & GICR_TYPER_VLPIS )
> +                    ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
> +            }
> +        } while ( !(typer & GICR_TYPER_LAST) );
> +    }
> +
> +    dprintk(XENLOG_WARNING, "CPU%d: mpidr %"PRIpaddr" has no re-distributor!\n",
> +                  smp_processor_id(), mpidr);

You are using PRIpaddr to print mpidr here, which is certainly not a
physical address. Please use the appropriate PRI macro and not just one
which happens to accept the correct sized argument.

> +    gicv3_redist_wait_for_rwp();
> +
> +    /* Enable system registers */
> +    gicv3_enable_sre();
> +
> +    WRITE_SYSREG32(0, ICC_BPR1_EL1);

Comment for this ^ write?

> +static void __cpuinit gicv3_hyp_init(void)
> +{
> +    uint32_t vtr;
> +
> +    vtr = READ_SYSREG32(ICH_VTR_EL2);
> +    nr_lrs  = (vtr & GICH_VTR_NRLRGS) + 1;
> +    nr_priorities = ((vtr >> GICH_VTR_PRIBITS_SHIFT) &
> +                    GICH_VTR_PRIBITS_MASK) + 1;
> +
> +    gic_ops.nr_lrs = nr_lrs;
> +
> +    WRITE_SYSREG32(GICH_VMCR_EOI | GICH_VMCR_VENG1, ICH_VMCR_EL2);
> +    WRITE_SYSREG32(GICH_HCR_EN, ICH_HCR_EL2);
> +
> +    update_cpu_lr_mask();
> +    vtr = READ_SYSREG32(ICH_HCR_EL2);

If this apparently redundant read actual serves a purpose (i.e. to
synchronise theh.w or something) then please add a comment.

> +static u16 gicv3_compute_target_list(int *base_cpu, const struct cpumask *mask,
> +                                   u64 cluster_id)
> +{
> +    int cpu = *base_cpu;
> +    u64 mpidr = cpu_logical_map(cpu);
> +    u16 tlist = 0;
> +
> +    while ( cpu < nr_cpu_ids )
> +    {
> +        /*
> +         * If we ever get a cluster of more than 16 CPUs, just
> +         * scream and skip that CPU.
> +         */
> +        if ( (mpidr & 0xff) >= 16 )
> +        {
> +            dprintk(XENLOG_WARNING, "Cluster more than 16's cpus\n");

"Cluster of" or "Cluster with".

This loop runs for every IPI we send. Perhaps we should validate this
sort of thing once at start of day and then assume that it is fine?

> +            goto out;
> +        }
> +        tlist |= 1 << (mpidr & 0xf);
> +
> +        cpu = cpumask_next(cpu, mask);

Aren't you essentially opencoding for_each_cpu with this check and the
while loop? 

The caller of this function already has a for_each_cpu in it. Can you
explain the algorithm please.

> +        if ( cpu == nr_cpu_ids )
> +        {
> +            cpu--;
> +            goto out;
> +        }
> +
> +        mpidr = cpu_logical_map(cpu);
> +        if ( cluster_id != (mpidr & ~0xffUL) ) {
> +            cpu--;
> +            goto out;
> +        }
> +    }
> +out:
> +    *base_cpu = cpu;
> +    return tlist;
> +}
> +
> +static void send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)

s/irq/sgi/ I think.

> +{
> +    u64 val;
> +
> +    val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48        |
> +           MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32        |
> +           irq << 24                                        |
> +           MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16        |

There's been a lot of open coded shifts throughout this code, I'm coming
to the conclusion that they need #defines so this code is more self
documenting (I was puzzled by the irq in the middle of all those
affinities).

> +           tlist);
> +
> +    WRITE_SYSREG(val, ICC_SGI1R_EL1);   
> +}
> +
> +static void gicv3_send_sgi(const cpumask_t *cpumask, enum gic_sgi sgi,
> +            uint8_t mode)
> +{
> +    int cpu = 0;
> +
> +    dsb();

The dsb() macro needs a scope parameter for a while now. Which version
of Xen is all this based on?

> +    for_each_cpu(cpu, cpumask)
> +    {
> +        u64 cluster_id = cpu_logical_map(cpu) & ~0xffUL;

Magic number.

> +static void gicv3_update_lr(int lr, struct pending_irq *p, unsigned int state)
> +{
> +    u64 grp = GICH_LR_GRP1;
> +    u64 val = 0;
> +
> +    BUG_ON(lr >= nr_lrs);
> +    BUG_ON(lr < 0);
> +
> +    val =  ((((u64)state) & 0x3) << GICH_LR_STATE_SHIFT) | grp |
> +        ((((u64)p->priority) & 0xff) << GICH_LR_PRIORITY_SHIFT) |
> +        (((u64)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);

Please can you try and do something about the visual clutter here.
Aligning things would be a good start. Perhaps some temporaries and/or
using "val |= XXX" might help too.

Are the & 0x3 and & 0xff really needed here? Aren't state and priority
constrained already?

> +
> +   if ( p->desc != NULL )
> +       val |= GICH_LR_HW |
> +         (((u64) p->desc->irq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT);
> +
> +    gich_write_lr(lr, val);
> +}
> +

> +static void gicv3_read_lr(int lr, struct gic_lr *lr_reg)
> +{
> +    u64 lrv;
> +    lrv = gich_read_lr(lr);
> +    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
> +    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK; 
> +    lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK;
> +    lr_reg->state    = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
> +    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;

Either line things up or don't

> +    lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;
> +}
> +
> +static void gicv3_write_lr(int lr_reg, struct gic_lr *lr)
> +{
> +    u64 lrv = 0;
> +    lrv = ( ((u64)(lr->pirq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT) |
> +        ((u64)(lr->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT) |
> +        ((u64)(lr->priority & GICH_LR_PRIORITY_MASK) << GICH_LR_PRIORITY_SHIFT) |
> +        ((u64)(lr->state & GICH_LR_STATE_MASK) << GICH_LR_STATE_SHIFT) |
> +        ((u64)(lr->hw_status & GICH_LR_HW_MASK)  << GICH_LR_HW_SHIFT)  |
> +        ((u64)(lr->grp & GICH_LR_GRP_MASK) << GICH_LR_GRP_SHIFT) );
> +    gich_write_lr(lr_reg, lrv);
> +}
> +
> +int gicv_v3_init(struct domain *d)
> +{
> +    int i;
> +    /*
> +     * Domain 0 gets the hardware address.
> +     * Guests get the virtual platform layout.
> +     */
> +    if ( d->domain_id == 0 )
> +    {
> +        d->arch.vgic.dbase = gic.dbase;
> +        d->arch.vgic.dbase_size = gic.dbase_size;
> +        for ( i = 0; i < gic.rdist_count; i++ )
> +        {
> +            d->arch.vgic.rbase[i] = gic.rdist_regions[i].rdist_base;
> +            d->arch.vgic.rbase_size[i] = gic.rdist_regions[i].rdist_base_size;
> +        }
> +        d->arch.vgic.rdist_stride = gic.rdist_stride;
> +        d->arch.vgic.rdist_count = gic.rdist_count;
> +    }
> +    else
> +    {

Does this need a comment like "Currently guests see a GICv2"? Otherwise
doesn't it need an rbase etc?

> +/* Set up the GIC */
> +static int __init gicv3_init(struct dt_device_node *node,
> +                                       const void *data)
> +{
> +    struct rdist_region *rdist_regs;
> +    int res, i;
> +    uint32_t reg;
> +
> +    dt_device_set_used_by(node, DOMID_XEN);
> +
> +    res = dt_device_get_address(node, 0, &gic.dbase, &gic.dbase_size);
> +    if ( res || !gic.dbase  || (gic.dbase & ~PAGE_MASK) ||
> +       (gic.dbase_size & ~PAGE_MASK) )
> +        panic("GIC: Cannot find a valid address for the distributor");

For the last two clauses printing the invalid values would be a useful
diagnostic (probably split into two ifs and two panics)

> +    gic.map_dbase = ioremap_nocache(gic.dbase, gic.dbase_size);
> +    if ( !gic.map_dbase )
> +        panic("Failed to ioremap for GIC distributor\n");

Please consistently prefix these "GIC:" (or better yet, GICv3)

> +
> +    reg = readl_relaxed(GICD + GICD_PIDR2);
> +    if ( (reg & GICD_PIDR2_ARCH_MASK) != GICD_PIDR2_GICV3 )
> +        panic("GIC: no distributor detected, giving up\n"); 

", giving up" is redundant in the context of a panic.

> +
> +    gic_ops.hw_version = GIC_V3;
> + 
> +    if ( !dt_property_read_u32(node, "#redistributor-regions",
> +                &gic.rdist_count) )
> +        gic.rdist_count = 1;
> +
> +    if ( gic.rdist_count > MAX_RDIST_COUNT )
> +        panic("GIC: Number of redistributor regions is more than \
> +               MAX_RDIST_COUNT (Increase MAX_RDIST_COUNT!!)\n");

Drop the parenthetical and print the actual and maximum values please.

> +
> +    rdist_regs = xzalloc_array(struct rdist_region, gic.rdist_count);
> +    if ( !rdist_regs )
> +        panic("GIC: no distributor detected, giving up\n");

This panic message does not match the context.

> +
> +    for ( i = 0; i < gic.rdist_count; i++ ) {
> +        u64 rdist_base, rdist_size;
> +
> +        res = dt_device_get_address(node, 1 + i, &rdist_base, &rdist_size);
> +        if ( res || !rdist_base)
> +            panic("No rdist base found\n");

Please print which one.

> +        rdist_regs[i].rdist_base = rdist_base;
> +        rdist_regs[i].rdist_base_size = rdist_size;
> +    }
> +
> +    if ( !dt_property_read_u32(node, "redistributor-stride", &gic.rdist_stride) )
> +        gic.rdist_stride = 0x0;

Somewhere else you had code to handle this with an if/else and explicit
increment. Why not just set this appropriately to start with and avoid
all that?

> +    for ( i = 0; i < gic.rdist_count; i++ ) {
> +        /* map dbase & rdist regions */
> +        gic.rdist_regions[i].map_rdist_base =
> +                ioremap_nocache(gic.rdist_regions[i].rdist_base,
> +                          gic.rdist_regions[i].rdist_base_size);
> +
> +        if ( !gic.rdist_regions[i].map_rdist_base )
> +            panic("Failed to ioremap for GIC redistributor\n");

Please print which one.

> +    }
> +
> +    printk("GIC initialization:\n"
> +              "        gic_dist_addr=%"PRIpaddr"\n"
> +              "        gic_dist_size=%"PRIpaddr"\n"
> +              "        gic_dist_mapaddr=%"PRIpaddr"\n"
> +              "        gic_rdist_regions=%d\n"
> +              "        gic_rdist_stride=%x\n"
> +              "        gic_rdist_base=%"PRIpaddr"\n"
> +              "        gic_rdist_base_size=%"PRIpaddr"\n"
> +              "        gic_rdist_base_mapaddr=%"PRIpaddr"\n"
> +              "        gic_maintenance_irq=%u\n",
> +              gic.dbase, gic.dbase_size, (u64)gic.map_dbase, gic.rdist_count,
> +              gic.rdist_stride, gic.rdist_regions[0].rdist_base,
> +              gic.rdist_regions[0].rdist_base_size,
> +              (u64)gic.rdist_regions[0].map_rdist_base, gic.maintenance.irq);

Print the stride perhaps?

Please removal all of the casts from this code and use the correct
format specifier instead.

As I've said before, a cast should almost never be needed.

> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 7489684..3c37120 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -18,6 +18,12 @@
>  #ifndef __ASM_ARM_GIC_H__
>  #define __ASM_ARM_GIC_H__
>  
> +#define SZ_64K  0x00010000

This isn't gic, or even ARM, specific. Please find a proper home for it.

> +#define NR_GIC_LOCAL_IRQS  NR_LOCAL_IRQS
> +#define NR_GIC_SGI         16
> +#define MAX_RDIST_COUNT    4

These should refer to GIC v3 in their names I think.

> +
>  /*
>   * The minimum GICC_BPR is required to be in the range 0-3. We set
>   * GICC_BPR to 0 but we must expect that it might be 3. This means we
> @@ -62,6 +68,13 @@
>  #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
>                          DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")

You should have one of these for GICv3 and use it.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-23 16:47         ` Julien Grall
@ 2014-04-23 17:03           ` Ian Campbell
  2014-04-23 17:09             ` Julien Grall
  2014-04-24  8:19           ` Ian Campbell
  1 sibling, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-23 17:03 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Wed, 2014-04-23 at 17:47 +0100, Julien Grall wrote:
> On 04/23/2014 04:01 PM, Julien Grall wrote:
> > On 04/23/2014 03:55 PM, Ian Campbell wrote:
> >> On Tue, 2014-04-15 at 19:35 +0100, Julien Grall wrote:
> >>>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> >>>> index eba41ee..2387e38 100644
> >>>> --- a/xen/include/asm-arm/gic.h
> >>>> +++ b/xen/include/asm-arm/gic.h
> >>>> @@ -43,12 +43,41 @@
> >>>>  #define SGI_TARGET_OTHERS  1
> >>>>  #define SGI_TARGET_SELF    2
> >>>>  
> >>>> +#define GICH_LR_PENDING    1
> >>>> +#define GICH_LR_ACTIVE     2
> >>>> +
> >>>
> >>> Prefixing by GICH_ is confusing. I though we were using it for to set
> >>> the value in the hardware. Can you rename it?
> >>
> >> This is code motion of an existing definition, definitely please don't
> >> rename it at the same time.
> >>
> >> But anyway, these are bits relating to the v2 GICH_LR register, which is
> >> the same on v3 as it happens. So I think the names are fine.
> > 
> > Reading again the code, you are right. I was confused then of the value
> > and the position at the same time.
> 
> After thinking it would be nice to keep the shift in it smth like:
> 
> #define GICH_LR_PENDING (1 << 0)
> #define GICH_LR_ACTION  (1 << 1)

That's going to be slightly misleading since those are the actual bit
positions, which are also different on gicv3.

This series is big enough as it is, no need to be bike shedding this
sort of thing, especially when this is only moving it to start with.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-23 17:03           ` Ian Campbell
@ 2014-04-23 17:09             ` Julien Grall
  2014-04-24  8:58               ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-23 17:09 UTC (permalink / raw)
  To: Ian Campbell
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/23/2014 06:03 PM, Ian Campbell wrote:
> On Wed, 2014-04-23 at 17:47 +0100, Julien Grall wrote:
>> On 04/23/2014 04:01 PM, Julien Grall wrote:
>>> On 04/23/2014 03:55 PM, Ian Campbell wrote:
>>>> On Tue, 2014-04-15 at 19:35 +0100, Julien Grall wrote:
>>>>>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>>>>>> index eba41ee..2387e38 100644
>>>>>> --- a/xen/include/asm-arm/gic.h
>>>>>> +++ b/xen/include/asm-arm/gic.h
>>>>>> @@ -43,12 +43,41 @@
>>>>>>  #define SGI_TARGET_OTHERS  1
>>>>>>  #define SGI_TARGET_SELF    2
>>>>>>  
>>>>>> +#define GICH_LR_PENDING    1
>>>>>> +#define GICH_LR_ACTIVE     2
>>>>>> +
>>>>>
>>>>> Prefixing by GICH_ is confusing. I though we were using it for to set
>>>>> the value in the hardware. Can you rename it?
>>>>
>>>> This is code motion of an existing definition, definitely please don't
>>>> rename it at the same time.
>>>>
>>>> But anyway, these are bits relating to the v2 GICH_LR register, which is
>>>> the same on v3 as it happens. So I think the names are fine.
>>>
>>> Reading again the code, you are right. I was confused then of the value
>>> and the position at the same time.
>>
>> After thinking it would be nice to keep the shift in it smth like:
>>
>> #define GICH_LR_PENDING (1 << 0)
>> #define GICH_LR_ACTION  (1 << 1)
> 
> That's going to be slightly misleading since those are the actual bit
> positions, which are also different on gicv3.
> 

I don't get your point here. This show only the bit position within the
field.

If this position is also different on GICv3 why this is common code? And
enhance GICH_ prefix which may lead to understand it's used to compute
HW lrs.

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-23 17:01   ` Ian Campbell
@ 2014-04-23 17:24     ` Julien Grall
  2014-04-29 12:35       ` Vijay Kilari
  2014-05-05 12:08     ` Vijay Kilari
  2014-05-27 18:17     ` Julien Grall
  2 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-23 17:24 UTC (permalink / raw)
  To: Ian Campbell
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/23/2014 06:01 PM, Ian Campbell wrote:
>> +    } while ( count-- );
>> +
>> +    if ( !count )
>> +        dprintk(XENLOG_WARNING, "RWP timeout\n");
> 
> Shouldn't we panic here?

I don't think panic is the solution here. This might be use on secondary
CPU.

IHMO, we should return an error code here an handle here upper in the
call stack.

>> +static void gicv3_restore_state(struct vcpu *v)
>> +{
>> +    int i;
>> +
>> +    for ( i = 0; i < nr_lrs; i++)
>> +        gich_write_lr(i, v->arch.gic.v3.lr[i]);
> 
> I wonder if the compiler could do a better job of this using the same
> switch and fallthrough method you used for aprn regs?

Marc has written a very nice solution for this stuff. It as written an
assembly function where all registers is save decreasing the number.

When the function, it will calculate the number of regs we don't need of
LRs save. This will avoid lots of jumps.

See code below (see http://permalink.gmane.org
/gmane.linux.ports.arm.kernel/310855 for the whole patch):

+	sub	w23, w23, w22	// How many regs we have to skip
+
+	adr	x24, 1f
+	add	x24, x24, x23, lsl #2
+	br	x24
+
+1:
+	mrs	x20, ICH_LR15_EL2
+	mrs	x19, ICH_LR14_EL2
+	mrs	x18, ICH_LR13_EL2
+	mrs	x17, ICH_LR12_EL2
+	mrs	x16, ICH_LR11_EL2
+	mrs	x15, ICH_LR10_EL2
+	mrs	x14, ICH_LR9_EL2
+	mrs	x13, ICH_LR8_EL2
+	mrs	x12, ICH_LR7_EL2
+	mrs	x11, ICH_LR6_EL2
+	mrs	x10, ICH_LR5_EL2
+	mrs	x9, ICH_LR4_EL2
+	mrs	x8, ICH_LR3_EL2
+	mrs	x7, ICH_LR2_EL2
+	mrs	x6, ICH_LR1_EL2
+	mrs	x5, ICH_LR0_EL2
+

[..]

>> +                return 0;
> 
> So basically we only know the number of redistributors from device tree
> and not the mapping from RDIST to CPU, so we have to try every one?
> 
> Do you have a reference to the GIC v3 Device Tree bindings? I don't see
> them in linux/Documentation/devicetree/bindings/.

GICv3 is not upstream for now. Marc as sent the V3 recently:

http://comments.gmane.org/gmane.linux.ports.arm.kernel/316902

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-23 16:47         ` Julien Grall
  2014-04-23 17:03           ` Ian Campbell
@ 2014-04-24  8:19           ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-24  8:19 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Wed, 2014-04-23 at 17:47 +0100, Julien Grall wrote:
> On 04/23/2014 04:01 PM, Julien Grall wrote:
> > On 04/23/2014 03:55 PM, Ian Campbell wrote:
> >> On Tue, 2014-04-15 at 19:35 +0100, Julien Grall wrote:
> >>>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> >>>> index eba41ee..2387e38 100644
> >>>> --- a/xen/include/asm-arm/gic.h
> >>>> +++ b/xen/include/asm-arm/gic.h
> >>>> @@ -43,12 +43,41 @@
> >>>>  #define SGI_TARGET_OTHERS  1
> >>>>  #define SGI_TARGET_SELF    2
> >>>>  
> >>>> +#define GICH_LR_PENDING    1
> >>>> +#define GICH_LR_ACTIVE     2
> >>>> +
> >>>
> >>> Prefixing by GICH_ is confusing. I though we were using it for to set
> >>> the value in the hardware. Can you rename it?
> >>
> >> This is code motion of an existing definition, definitely please don't
> >> rename it at the same time.
> >>
> >> But anyway, these are bits relating to the v2 GICH_LR register, which is
> >> the same on v3 as it happens. So I think the names are fine.
> > 
> > Reading again the code, you are right. I was confused then of the value
> > and the position at the same time.
> 
> After thinking it would be nice to keep the shift in it smth like:
> 
> #define GICH_LR_PENDING (1 << 0)
> #define GICH_LR_ACTION  (1 << 1)

That's going to be slightly misleading since those are not the actual
bit positions, but rather the offset into the field. The overall offset
is also different on gicv3, whereas the individual bits within the field
are the same.

This series is big enough as it is, no need to be bike shedding this
sort of thing, especially when this is only moving it to start with.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-23 17:09             ` Julien Grall
@ 2014-04-24  8:58               ` Ian Campbell
  0 siblings, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-24  8:58 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Wed, 2014-04-23 at 18:09 +0100, Julien Grall wrote:
> On 04/23/2014 06:03 PM, Ian Campbell wrote:
> > On Wed, 2014-04-23 at 17:47 +0100, Julien Grall wrote:
> >> On 04/23/2014 04:01 PM, Julien Grall wrote:
> >>> On 04/23/2014 03:55 PM, Ian Campbell wrote:
> >>>> On Tue, 2014-04-15 at 19:35 +0100, Julien Grall wrote:
> >>>>>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> >>>>>> index eba41ee..2387e38 100644
> >>>>>> --- a/xen/include/asm-arm/gic.h
> >>>>>> +++ b/xen/include/asm-arm/gic.h
> >>>>>> @@ -43,12 +43,41 @@
> >>>>>>  #define SGI_TARGET_OTHERS  1
> >>>>>>  #define SGI_TARGET_SELF    2
> >>>>>>  
> >>>>>> +#define GICH_LR_PENDING    1
> >>>>>> +#define GICH_LR_ACTIVE     2
> >>>>>> +
> >>>>>
> >>>>> Prefixing by GICH_ is confusing. I though we were using it for to set
> >>>>> the value in the hardware. Can you rename it?
> >>>>
> >>>> This is code motion of an existing definition, definitely please don't
> >>>> rename it at the same time.
> >>>>
> >>>> But anyway, these are bits relating to the v2 GICH_LR register, which is
> >>>> the same on v3 as it happens. So I think the names are fine.
> >>>
> >>> Reading again the code, you are right. I was confused then of the value
> >>> and the position at the same time.
> >>
> >> After thinking it would be nice to keep the shift in it smth like:
> >>
> >> #define GICH_LR_PENDING (1 << 0)
> >> #define GICH_LR_ACTION  (1 << 1)
> > 
> > That's going to be slightly misleading since those are the actual bit
> > positions, which are also different on gicv3.
> > 
> 
> I don't get your point here. This show only the bit position within the
> field.

Writing GICH_LR_PENDING as (1 << 0)  as you are suggesting would look
like the pending bit was bit 0 of the relevant register, and would not
IMHO improve the clarity.

> If this position is also different on GICv3 why this is common code? And
> enhance GICH_ prefix which may lead to understand it's used to compute
> HW lrs.

On gic v2 GICH_LRn.[29:28] are the state field. On gic v3
ICH_LRn_EL2.[63:32] are the state field. Both field are defined to have
the same values (gic v3 literally says "as for gic v2"), and is defined
as:
        00 invalid
        01 pending
        10 active
        11 pending and active.
which is what the #defines above are.

Anyway, whether or not this should be changed I don't think this series
is the place to do it, it is big enough and unwieldy enough as it is and
Vijay has plenty of stuff on his plate without tacking arbitrary
cleanups on to it just because he happens to move the code around. If it
bothers you so much then please send a patch *after* the gic v3 support
is committed.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 14/16] xen/arm: Add virtual GICv3 support
  2014-04-15 11:17 ` [PATCH v3 14/16] xen/arm: Add virtual GICv3 support vijay.kilari
  2014-04-17  9:27   ` Julien Grall
@ 2014-04-24 10:30   ` Ian Campbell
  2014-05-02  9:43     ` Vijay Kilari
  1 sibling, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-24 10:30 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Add virtual GICv3 driver support
> 
> This patch adds only basic v3 support.
> Does not support Interrupt Translation support (ITS)
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/Makefile             |    2 +-
>  xen/arch/arm/vgic-v3.c            |  835 +++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic.c               |    4 +-
>  xen/include/asm-arm/gic_v3_defs.h |    2 +
>  xen/include/asm-arm/vgic.h        |    9 +-
>  5 files changed, 849 insertions(+), 3 deletions(-)
> 
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 39166aa..d269191 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -26,7 +26,7 @@ obj-y += smpboot.o
>  obj-y += smp.o
>  obj-y += shutdown.o
>  obj-y += traps.o
> -obj-y += vgic.o vgic-v2.o
> +obj-y += vgic.o vgic-v3.o vgic-v2.o
>  obj-y += vtimer.o
>  obj-y += vuart.o
>  obj-y += hvm.o
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> new file mode 100644
> index 0000000..e3d773a
> --- /dev/null
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -0,0 +1,835 @@
> +/*
> + * xen/arch/arm/vgic-v3.c
> + *
> + * ARM Virtual Generic Interrupt Controller v3 support
> + * based on xen/arch/arm/vgic.c
> + *
> + * Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
> + * Copyright (c) 2014 Cavium Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/bitops.h>
> +#include <xen/config.h>
> +#include <xen/lib.h>
> +#include <xen/init.h>
> +#include <xen/softirq.h>
> +#include <xen/irq.h>
> +#include <xen/sched.h>
> +
> +#include <asm/current.h>
> +#include <asm/device.h>
> +
> +#include <asm/mmio.h>
> +#include <asm/gic_v3_defs.h>
> +#include <asm/gic.h>
> +#include <asm/vgic.h>
> +
> +#define REG(n) (n)
> +
> +/*
> + * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
> + * <b>-bits-per-interrupt.
> + */
> +/* Shift n >> 2 to make it byte register diff */

These two comments should be merged.

What is a "byte register diff"? Do you mean offset in bytes?

The shift still confuses me, even with the comment. Isn't it shifting
the wrong way to convert something to bytes?

> +#define REG_RANK_INDEX(b, n) (((n) >> 2) & ((b)-1))
> +
> +/*
> + * Returns rank corresponding to a GICD_<FOO><n> register for
> + * GICD_<FOO> with <b>-bits-per-interrupt.
> + */
> +static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
> +{
> +    int rank;
> +
> +    /* divide by 4 to make it byte size register difference
> +      as n is difference of 4 byte size register */
> +    n = n >> 2;

I'm confused again by this comment, if the input n is at word
granularity why divide and not multiple to get bytes? Or maybe the
comment is backwards and you have bytes and want a word sized offset?

> +    rank  = REG_RANK_NR(b, n);
> +
> +    return vgic_get_irqrank(v, rank);
> +}
> +
> +static int vgic_read_priority(struct vcpu *v, int irq)

Please can you do as you have done for the physical gic and name these
vgicv3 (and likewise in an earlier patch for v2).

> +static int __vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info,
> +           uint32_t offset)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +    int gicr_reg = REG(offset);
> +    u64 mpidr;
> +    u64 aff;

Please use uint64_t throughout.

> +
> +    switch ( gicr_reg )
> +    {
> +    case GICR_CTLR:
> +        /* We have implemented LPI's, read zero */
> +        goto read_as_zero;
> +    case GICR_IIDR:

Size check? Many of the cases which aren't read_as_zero seem to to miss
these.

> +        *r = GICR_IIDR_VAL;
> +        return 1;
> +    case GICR_TYPER:
> +        mpidr = cpu_logical_map(smp_processor_id());
> +        aff  = mpidr & ((1 << 24) - 1);
> +        aff |= (mpidr >> 8) & (0xffUL << 24);
> +        aff = aff << 32;
> +        aff = (aff | ((u64)smp_processor_id() << 8));
> +        aff = (aff | (0x9UL << 0));

Didn't you define a macro in an earlier patch to help with all this bit
manipulation?

Please also comment on the magic numbers, like 0x9UL, or use #defines.

Please either align = signs or don't, not a mixture.

> +        *r = aff;
> +        return 1;
> +    case GICR_STATUSR:
> +        /* Not implemented */

For optional registers which are not implemented can you please comment
as /* Optional register, unimplemented, RAZ/WI */ or something so we can
see at a glance why they are not implemented.

Since this is optional I suppose there must be a register somewhere
which announces the presence/absence? If so please can you add a comment
in the read of that register describing what the value you are returning
implies.

> +        goto read_as_zero;
> +    case GICR_WAKER:
> +        /* Not implemented */

Is this a secure only register? If yes then please say so in the
comment.

> +        goto read_as_zero;
> +    case GICR_SETLPIR:
> +    case GICR_CLRLPIR:
> +        /* WO return fail */
> +        return 0;

What is the defined/expected hardware behaviour if you read this
register? Read garbage or trap?

> +static int __vgic_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info,
> +          uint32_t offset)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +    int gicr_reg = REG(offset);
> +
> +    switch ( gicr_reg )
> +    {
> +    case GICR_CTLR:
> +        /* We do not implement LPI's, read zero */

This is the write handler.

> +    case GICR_NSACR:
> +        if ( dabt.size != 2 ) goto bad_width;

Read ignored? Should this read as zero or??

> +    case GICR_ISPENDR0:
> +        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
> +        return 0;
> +    case GICR_ICPENDR0:
> +        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
> +        return 0;

v2 prints for both of these. Maybe that isn't wise? In any case a
comment here to explain what's happening would be nice.


> +    case GICR_ICFGR0:
> +        /* RO */

Missing goto.

> +static int vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info)
> +{
> +    uint32_t offset;
> +
> +    if ( !v->domain->arch.vgic.rdist_stride )
> +        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
> +    else
> +        offset = info->gpa & 0x1FFFF;

Please initialiase rdist_stride to a default which would cause this same
behaviour when it is not explicit and avoid the conditional here. 

> +
> +    if ( offset < SZ_64K )
> +       return __vgic_rdistr_mmio_read(v, info, offset);
> +    else if ( (offset - SZ_64K) < SZ_64K )

Can you write this as if ( offset > SZ_64K && offset < 2*SZ_64K )
please. (with <=/>= as appropriate)

> +       return vgic_rdistr_sgi_mmio_read(v, info, (offset - SZ_64K));
> +    else
> +       dprintk(XENLOG_WARNING, "vGICR: wrong gpa read address %"PRIpaddr"\n",

s/wrong/unknown/

I guess we don't know the rdist number here? Maybe it isn't worth
logging in any case.

> +               info->gpa);
> +    return 0;
> +}
> +
> +static int vgic_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info)

All the same comments as the read case.

> +{
> +    uint32_t offset;
> +
> +    if ( !v->domain->arch.vgic.rdist_stride )
> +        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
> +    else
> +        offset = info->gpa & 0x1FFFF;
> +
> +    if ( offset < SZ_64K )
> +       return __vgic_rdistr_mmio_write(v, info, offset);

Please name this vgic_rdistr_FOO_mmio_write where FOO is some name to
distinguish from the sgi region. (likewise the read variant)

> +    else if ( (offset - SZ_64K) < SZ_64K )
> +       return vgic_rdistr_sgi_mmio_write(v, info, (offset - SZ_64K));
> +    else
> +       dprintk(XENLOG_WARNING, "vGICR: wrong gpa write %"PRIpaddr"\n",
> +               info->gpa);
> +    return 0;
> +}
> +
> +static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
> +{
> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +    struct vgic_irq_rank *rank;
> +    int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
> +    int gicd_reg = REG(offset);
> +
> +    switch ( gicd_reg )
> +    {
> +    case GICD_CTLR:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        vgic_lock(v);
> +        *r = v->domain->arch.vgic.ctlr;
> +        vgic_unlock(v);
> +        return 1;
> +    case GICD_TYPER:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        /* No secure world support for guests. */
> +        vgic_lock(v);
> +        *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS )
> +            |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES );
> +        vgic_unlock(v);
> +        return 1;
> +    case GICD_STATUSR:
> +        /* Not implemented */
> +        goto read_as_zero;
> +    case GICD_IIDR:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        /*
> +         * XXX Do we need a JEP106 manufacturer ID?
> +         * Just use the physical h/w value for now
> +         */

I think this comment wuld be better at the definition of GICD_IIDR_VAL.

> +    case GICD_IROUTER ... GICD_IROUTERN:
> +        rank = vgic_irq_rank(v, 64, gicd_reg - GICD_IROUTERN);
> +        if ( rank == NULL) goto read_as_zero;
> +
> +        vgic_lock_rank(v, rank);
> +        /* IROUTER is 64 bit so, to make it byte size right shift by 3.
> +           Here once. macro REG_RANK_INDEX will do it twice */

Then REG_RANK_INDEX is buggy I think, since you pass it 64 indicating
that you want the index of a 64 bit register based on the given offset
and that is what it should return without needing to massage the input
as well.

> +    case GICD_PIDR7... GICD_PIDR0:

Width check (I expect elsewhere in this file too)

> +        /* GICv3 identification value */
> +        *r = GICD_PIDR0_GICV3;
> +        return 1;
> +    case REG(0x00c):
> +    case REG(0x044):
> +    case REG(0x04c):
> +    case REG(0x05c) ... REG(0x07c):
> +    case REG(0xf30) ... REG(0x5fcc):
> +    case REG(0x8000) ... REG(0xbfcc):
> +    case REG(0xc000) ... REG(0xffcc):

What distinguishes these registers from those captured by the default
clause? Are these unimplemented implementation defined registers? Is
there a reason to expect a guest to legitimately prod them?

Please comment (or remove in favour of the default case).
+
> +    /* R/O -- write ignored */
> +    case GICD_TYPER:

Either fall through for all or none please.

> +    case GICD_ISENABLER ... GICD_ISENABLERN:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
> +        if ( rank == NULL) goto write_ignore;
> +        vgic_lock_rank(v, rank);
> +        tr = rank->ienable;
> +        rank->ienable |= *r;
> +        vgic_unlock_rank(v, rank);
> +        vgic_enable_irqs(v, (*r) & (~tr), (gicd_reg - GICD_ISENABLER) >> 2);


I'd prefer this shift to be part of the implementation if
vgic_enable_irqs if possible, or to use one of the macros which does
these sorts of conversions (or a new one if nothing existing suites)


> +        return 1;
> +    case GICD_ICENABLER ... GICD_ICENABLERN:
> +        if ( dabt.size != 2 ) goto bad_width;
> +        rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
> +        if ( rank == NULL) goto write_ignore;
> +        vgic_lock_rank(v, rank);
> +        tr = rank->ienable;
> +        rank->ienable &= ~*r;
> +        vgic_unlock_rank(v, rank);
> +        vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER);

No shift for the disable case?

> +    case GICD_IROUTER ... GICD_IROUTER + 8*7:

What is 8*7? Please comment, or better yet use a #define.

> +        /* SGI/PPI target is read only */
> +        goto write_ignore;
> +    case GICD_IROUTER + 8*8 ... GICD_IROUTERN:
> +        rank = vgic_irq_rank(v, 64, gicd_reg - GICD_IROUTER);
> +        if ( rank == NULL) goto write_ignore;
> +        vgic_lock_rank(v, rank);
> +        rank->irouter[REG_RANK_INDEX(64, (gicd_reg - GICD_IROUTER)>>1)] = *r;
> +        vgic_unlock_rank(v, rank);
> +        return 1;
> +    case GICD_IPRIORITYR ... GICD_IPRIORITYRN:

> +    case REG(0x00c):
> +    case REG(0x044):
> +    case REG(0x04c):
> +    case REG(0x05c) ... REG(0x07c):
> +    case REG(0xf30) ... REG(0x5fcc):
> +    case REG(0x8000) ... REG(0xbfcc):
> +    case REG(0xc000) ... REG(0xffcc):
> +        printk("vGICD: write unknown 0x00c 0xfcc  r%d offset %#08x\n", dabt.reg, offset);

0x00c 0xfcc hardcoded in the message? Needs a comment or to be merged
with the default case.

> +static int vgic_domain_init(struct domain *d)
> +{
> +    int i;
> +
> +    vgic_distr_mmio_handler.addr = d->arch.vgic.dbase;
> +    vgic_distr_mmio_handler.size = d->arch.vgic.dbase_size;
> +    register_mmio_handler(d, &vgic_distr_mmio_handler);

Using a global struct like this is invalid since you store a pointer to
it and not a copy.

> +    for ( i = 0; i < d->arch.vgic.rdist_count; i++ )
> +    {
> +        vgic_rdistr_mmio_handler.addr = d->arch.vgic.rbase[i];
> +        vgic_rdistr_mmio_handler.size = d->arch.vgic.rbase_size[i];
> +        register_mmio_handler(d, &vgic_rdistr_mmio_handler);

Can we processes the rdistr stride here (or when we setup
d->arch.vgic.rbase*) and register the sgi region separately?

> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index f487784..0ad5e51 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -62,7 +62,9 @@ int domain_vgic_init(struct domain *d)
>      else
>          d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
>  
> -    if ( gic_hw_version() == GIC_V2 )
> +    if ( gic_hw_version() == GIC_V3 )
> +        vgic_v3_init(d);
> +    else if ( gic_hw_version() == GIC_V2 )
>          vgic_v2_init(d);

When dealing with enums please use a switch.

>      else
>          panic("No VGIC found\n");
> diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
> index 578832b..f7f7932 100644
> --- a/xen/include/asm-arm/gic_v3_defs.h
> +++ b/xen/include/asm-arm/gic_v3_defs.h
> @@ -94,6 +94,8 @@
>  #define GICD_PIDR2_ARCH_MASK          (0xf0)
>  #define GICR_PIDR2_ARCH_MASK          GICD_PIDR2_ARCH_MASK
>  #define GICR_SYNCR_NOT_BUSY           1
> +#define GICD_IIDR_VAL                 0x34c

That comment about JDEC etc should go here somewhere I think.

> +#define GICR_IIDR_VAL                 GICD_IIDR_VAL
>  
>  #define GICR_CTLR       (0x0000)
>  #define GICR_IIDR       (0x0004)
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index 187846e..0de74eb 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -25,7 +25,10 @@ struct vgic_irq_rank {
>      uint32_t ienable, iactive, ipend, pendsgi;
>      uint32_t icfg[2];
>      uint32_t ipriority[8];
> -    uint32_t itargets[8];
> +    union {
> +        uint32_t itargets[8];
> +        uint64_t irouter[32];

itargets is v2 specific and irouter v3, right? In which case please do
    union {
        struct {
            uint32_t itargets[8];
        } v2;
        struct {
            uint64_t irouter[32];
        } v3;
    }

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 14/16] xen/arm: Add virtual GICv3 support
  2014-04-17  9:27   ` Julien Grall
@ 2014-04-24 10:37     ` Ian Campbell
  2014-04-24 11:39       ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-24 10:37 UTC (permalink / raw)
  To: Julien Grall
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On Thu, 2014-04-17 at 10:27 +0100, Julien Grall wrote:
> > +        return 0;
> > +    case GICR_SYNCR:
> > +        if ( dabt.size != 2 ) goto bad_width;
> > +        /* RO */
> > +        /* Return as not busy */
> > +        *r = GICR_SYNCR_NOT_BUSY;
> 
> Please explain why this value.

Doesn't the comment already do so?

> > +        return 0;
> > +    case GICR_PIDR7... GICR_PIDR0:

Strange ordering, and whitespace incorrect.

> > +        *r = GICR_PIDR0_GICV3;
> 
> Hrrmmm... no. PIDR1 should return 0xB (on ARM implementation)...

It's certainly odd to return PIDR0 for all 7 registers.

It's not clear that returning the ARM values is the right thing to do,
but this is similar to the JEP106 thing in GICD_IIDR.

> > +    /* Implementation defined -- read as zero */
> > +    case REG(0x020) ... REG(0x03c):
> 
> Please move the comment after the case.
> 
> Also can you give a name to this register? For clarity.

They are implementation defined, so no I would say. The existing code
does the same, it is fine IMHO.

> > @@ -51,6 +54,9 @@ static inline int REG_RANK_NR(int b, uint32_t n)
> >  {
> >      switch ( b )
> >      {
> > +    case 64: return n >> 6;
> > +    case 32: return n >> 5;
> > +    case 16: return n >> 4;
> 
> It doesn't sounds right to update this common function. What happen if
> VGIC v2 is trying to use this value?

These are correct responses to being passed those values of b and n, I
think this is absolutely fine to do this in a common place.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information
  2014-04-15 11:17 ` [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information vijay.kilari
  2014-04-18 19:57   ` Julien Grall
@ 2014-04-24 10:46   ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-24 10:46 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Update GIC device tree node for DOM0 with GICv3
> information. GIC hw specfic device tree information
> is moved to respective GIC driver.

Please add a reference to the relevant bindings document. NB this
probably does mean that much of this series is blocked on that binding
being formalised (AKA committed to
linux/Docuemtnation/devicetree/bindings at the moment), so please let us
know when that has happened.

> diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
> index 1e62dd9..cacb9e4 100644
> --- a/xen/arch/arm/gic-v2.c
> +++ b/xen/arch/arm/gic-v2.c
> @@ -487,6 +487,14 @@ static unsigned int gicv2_read_vmcr_priority(void)
>     return (GICH[GICH_VMCR] >> GICH_VMCR_PRIORITY_SHIFT) & GICH_VMCR_PRIORITY_MASK;
>  }
>  
> +int static gicv3_make_dt_node(const struct domain *d,
> +              const struct dt_device_node *node, void *fdt, __be32 *cells)
> +{
> +    dt_set_range(&cells, node, d->arch.vgic.dbase, PAGE_SIZE);
> +    dt_set_range(&cells, node, d->arch.vgic.cbase, PAGE_SIZE * 2);

No rdist? 

Oh wait, this is gic-v2.c, so your function name is just wrong.

> +    return 0;
> +}
> +
>  static hw_irq_controller irq_ops = {
>      .enable              = gicv2_enable_irq,
>      .disable             = gicv2_disable_irq,
> @@ -512,6 +520,7 @@ static struct gic_hw_operations gic_ops = {
>      .read_lr             = gicv2_read_lr,
>      .write_lr            = gicv2_write_lr,
>      .read_vmcr_priority  = gicv2_read_vmcr_priority,
> +    .make_dt_node        = gicv3_make_dt_node,
>  };
>  
>  static const char * const gicv2_dt_compat[] __initconst =
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index 8625e0c..e27b094 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -30,6 +30,7 @@
>  #include <xen/softirq.h>
>  #include <xen/list.h>
>  #include <xen/device_tree.h>
> +#include <xen/libfdt/libfdt.h>
>  #include <xen/delay.h>
>  #include <asm/p2m.h>
>  #include <asm/domain.h>
> @@ -825,6 +826,37 @@ static unsigned int gicv3_read_vmcr_priority(void)
>              GICH_VMCR_PRIORITY_MASK);
>  }
>  
> +int static gicv3_make_dt_node(const struct domain *d,
> +              const struct dt_device_node *node, void *fdt, __be32 *cells)
> +{
> +    uint32_t rd_stride = 0;
> +    uint32_t rd_count = 0;
> +    int res, i;
> +
> +    const struct dt_device_node *gic = dt_interrupt_controller;
> +    res = dt_property_read_u32(gic, "redistributor-stride", &rd_stride);
> +    if ( !res )
> +        rd_stride = 0;
> +
> +    res = dt_property_read_u32(gic, "#redistributor-regions", &rd_count);
> +    if ( !res )
> +        rd_count = 1;

This is passing on the physical values, which is only correct for dom0.
For domU you need to get these values from d->arch.vgic, which is where
they should come from for dom0 too.

That might mean you can drop the fdt param? If you do keep it then
please make the prototype of the function match the similar functions
throughout domain_build.c., which is (d, fdt, node)

Which also means you should drop the cells argument and handle it within
each callback, the existing one isn't big enough for gicv3 anyway. 

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-04-15 11:17 ` [PATCH v3 16/16] xen/arm: add SGI handling for GICv3 vijay.kilari
  2014-04-18 20:20   ` Julien Grall
@ 2014-04-24 10:57   ` Ian Campbell
  2014-04-24 11:43     ` Julien Grall
  1 sibling, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-24 10:57 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	xen-devel, stefano.stabellini

On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:

> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index e3d773a..2bef977 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -774,6 +774,85 @@ write_ignore:
>      return 1;
>  }
>  
> +static int vgic_to_sgi(struct vcpu *v, register_t sgir)
> +{
> +    struct domain *d = v->domain;
> +    int virq;
> +    int irqmode;
> +    int vcpuid;
> +    int i;
> +    unsigned long vcpu_mask = 0;
> +
> +    ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));

We get away with an unsigned long and ASSERT on v2 because it is limited
to 8 cpus, but gic v3 supports many more. You didn't change
MAX_VIRT_CPUS in this series, did you? In which case I suppose this is
safe enough for now, but will need to be cleverer at some point in the
future.

> +    irqmode = (sgir >> ICH_SGI_IRQMODE_SHIFT) & ICH_SGI_IRQMODE_MASK;
> +    virq = (sgir >> ICH_SGI_IRQ_SHIFT ) & ICH_SGI_IRQ_MASK;
> +
> +    ASSERT( virq < 16 );

The rest of this function is identical to vgic_to_sgi, I think. Please
can you make both call a common function after decoding the register.
	vgic_cpu_inject_sgi(..., irqmode, virq);

> +static int vgic_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr)
> +{
> +    struct vcpu *v = current;
> +    struct hsr_sysreg sysreg = hsr.sysreg;
> +    register_t *r = select_user_reg(regs, sysreg.reg);
> +    switch ( hsr.bits & HSR_SYSREG_REGS_MASK )
> +    {
> +    case HSR_SYSREG_ICC_SGI1R_EL1:
> +        /* WO */
> +        if ( !sysreg.read )
> +            return vgic_to_sgi(v, *r);
> +        else
> +        {
> +            gdprintk(XENLOG_WARNING, "Reading SGI1R_EL1 - WO register\n");
> +            return 0;
> +        }
> +    default:
> +        return 0;
> +    }
> +}
> +
> +int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
> +{
> +    switch ( hsr.ec )
> +    {
> +    case HSR_EC_SYSREG:

This is only called from do_sysreg, which is already in the
HSR_EC_SYSREG branch, so this whole function is redundant, unless you
expect there to be a v7 version of the sysreg gic interface?

I think you can move the body of vgic_emulate_sysreg into vgic_emulate
and simply ASSERT(hsr.ec == HSR_EC_SYSREG).

> diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h
> index 0cee0e9..18e5a45 100644
> --- a/xen/include/asm-arm/sysregs.h
> +++ b/xen/include/asm-arm/sysregs.h
> @@ -56,7 +56,7 @@
>  #define HSR_SYSREG_CNTP_CTL_EL0   HSR_SYSREG(3,3,c14,c2,1)
>  #define HSR_SYSREG_CNTP_TVAL_EL0  HSR_SYSREG(3,3,c14,c2,0)
>  
> -
> +#define HSR_SYSREG_ICC_SGI1R_EL1  HSR_SYSREG(3,0,c12,c11,5)

Please sort into the correct order (which is by the order of the
arguments)

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 14/16] xen/arm: Add virtual GICv3 support
  2014-04-24 10:37     ` Ian Campbell
@ 2014-04-24 11:39       ` Julien Grall
  0 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-24 11:39 UTC (permalink / raw)
  To: Ian Campbell
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/24/2014 11:37 AM, Ian Campbell wrote:
> On Thu, 2014-04-17 at 10:27 +0100, Julien Grall wrote:
>>> +        return 0;
>>> +    case GICR_SYNCR:
>>> +        if ( dabt.size != 2 ) goto bad_width;
>>> +        /* RO */
>>> +        /* Return as not busy */
>>> +        *r = GICR_SYNCR_NOT_BUSY;
>>
>> Please explain why this value.
> 
> Doesn't the comment already do so?

Hmmm ... right, I don't remember why I though a better comment was needed.


>>> +        return 0;
>>> +    case GICR_PIDR7... GICR_PIDR0:
> 
> Strange ordering, and whitespace incorrect.
> 
>>> +        *r = GICR_PIDR0_GICV3;
>>
>> Hrrmmm... no. PIDR1 should return 0xB (on ARM implementation)...
> 
> It's certainly odd to return PIDR0 for all 7 registers.
> 
> It's not clear that returning the ARM values is the right thing to do,
> but this is similar to the JEP106 thing in GICD_IIDR.
> 
>>> +    /* Implementation defined -- read as zero */
>>> +    case REG(0x020) ... REG(0x03c):
>>
>> Please move the comment after the case.
>>
>> Also can you give a name to this register? For clarity.
> 
> They are implementation defined, so no I would say. The existing code
> does the same, it is fine IMHO.

I've noticed this part after I wrote my email.

> 
>>> @@ -51,6 +54,9 @@ static inline int REG_RANK_NR(int b, uint32_t n)
>>>  {
>>>      switch ( b )
>>>      {
>>> +    case 64: return n >> 6;
>>> +    case 32: return n >> 5;
>>> +    case 16: return n >> 4;
>>
>> It doesn't sounds right to update this common function. What happen if
>> VGIC v2 is trying to use this value?
> 
> These are correct responses to being passed those values of b and n, I
> think this is absolutely fine to do this in a common place.

I agree with you. With this change, if the VGICv2 emulation decides to
use this value by mistake, the code doesn't hit the BUG_ON anymore.

On another side the call site of this function check if the rank is
valid... So I guess it's fine.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-04-24 10:57   ` Ian Campbell
@ 2014-04-24 11:43     ` Julien Grall
  0 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-24 11:43 UTC (permalink / raw)
  To: Ian Campbell
  Cc: vijay.kilari, stefano.stabellini, Prasun.Kapoor, vijaya.kumar,
	xen-devel, stefano.stabellini

On 04/24/2014 11:57 AM, Ian Campbell wrote:
> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> 
>> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
>> index e3d773a..2bef977 100644
>> --- a/xen/arch/arm/vgic-v3.c
>> +++ b/xen/arch/arm/vgic-v3.c
>> @@ -774,6 +774,85 @@ write_ignore:
>>      return 1;
>>  }
>>  
>> +static int vgic_to_sgi(struct vcpu *v, register_t sgir)
>> +{
>> +    struct domain *d = v->domain;
>> +    int virq;
>> +    int irqmode;
>> +    int vcpuid;
>> +    int i;
>> +    unsigned long vcpu_mask = 0;
>> +
>> +    ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));
> 
> We get away with an unsigned long and ASSERT on v2 because it is limited
> to 8 cpus, but gic v3 supports many more. You didn't change
> MAX_VIRT_CPUS in this series, did you? In which case I suppose this is
> safe enough for now, but will need to be cleverer at some point in the
> future.

I didn't see any change of MAX_VIRT_CPUS in this series. If he plans to
change it in a next version, we have to check a domain doesn't start
with more than 8 CPUs when it's using VGICv2 emulation.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call
  2014-04-23 14:32   ` Ian Campbell
@ 2014-04-25  9:28     ` Vijay Kilari
  0 siblings, 0 replies; 107+ messages in thread
From: Vijay Kilari @ 2014-04-25  9:28 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Wed, Apr 23, 2014 at 8:02 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> othercpu parameter in do_sgi is unused
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>
> Acked-by: Ian Campbell <ian.campbell@citrix.com>
>
> I take it gic v3 doesn't tell us who sent an SGI?

yes correct.
>
>

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-15 18:35   ` Julien Grall
  2014-04-23 14:55     ` Ian Campbell
@ 2014-04-28 11:48     ` Vijay Kilari
  2014-04-28 12:06       ` Julien Grall
  1 sibling, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-04-28 11:48 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Wed, Apr 16, 2014 at 12:05 AM, Julien Grall <julien.grall@linaro.org> wrote:
> Hello Vijaya,
>
> Thank you for the patch.
>
>>      /* Enable routing */
>> -    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
>> +    gic_hw_ops->gic_irq_ops->enable(desc);
>
> This is not the right way to use gic_irq_ops. You should directly
> assigned this structure to desc->handler.
>
 I think desc->handler is already filled with ops of below struct
which is used

static hw_irq_controller gic_host_irq_type = {
    .typename = "gic",
    .startup = gic_irq_startup,
    .shutdown = gic_irq_shutdown,
    .enable = gic_irq_enable,
    .disable = gic_irq_disable,
    .ack = gic_irq_ack,
    .end = gic_host_irq_end,
    .set_affinity = gic_irq_set_affinity,
};

> I guess you don't do it because you have the desc->status and gic_lock
> locking which is common.
>
> IHMO, you have to let the GICv{2,3} drivers handling their own lock for
> the hardware access.

The existing lock gic_lock protects both generic & hw specific functionality.
So I could not see need for another level of locking. Anything specific that
you see it is missing?

Regards
Vijay

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-28 11:48     ` Vijay Kilari
@ 2014-04-28 12:06       ` Julien Grall
  2014-04-28 13:10         ` Vijay Kilari
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-04-28 12:06 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

Hello Vijaya

On 04/28/2014 12:48 PM, Vijay Kilari wrote:
> On Wed, Apr 16, 2014 at 12:05 AM, Julien Grall <julien.grall@linaro.org> wrote:
>> Thank you for the patch.
>>
>>>      /* Enable routing */
>>> -    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
>>> +    gic_hw_ops->gic_irq_ops->enable(desc);
>>
>> This is not the right way to use gic_irq_ops. You should directly
>> assigned this structure to desc->handler.
>>
>  I think desc->handler is already filled with ops of below struct
> which is used

No, with your patch, the desc->handler is filled with ops from the
generic code. You added an indirection to call the specific ops.

In any case, you are only partially define the ops here, which is wrong.
Every callbacks should be defined for consistency.

> static hw_irq_controller gic_host_irq_type = {
>     .typename = "gic",
>     .startup = gic_irq_startup,
>     .shutdown = gic_irq_shutdown,
>     .enable = gic_irq_enable,
>     .disable = gic_irq_disable,
>     .ack = gic_irq_ack,
>     .end = gic_host_irq_end,
>     .set_affinity = gic_irq_set_affinity,
> };
> 
>> I guess you don't do it because you have the desc->status and gic_lock
>> locking which is common.
>>
>> IHMO, you have to let the GICv{2,3} drivers handling their own lock for
>> the hardware access.
> 
> The existing lock gic_lock protects both generic & hw specific functionality.
> So I could not see need for another level of locking. Anything specific that
> you see it is missing?

I don't see why you are saying : "The gic_lock protected generic
functionality".
I've looked at the code and the gic.lock is only used to protect call to
gic callback.
The gic_lock has been designed to protect access to the hardware, *NOT*
the internal structure.

IHMO, this lock should be moved in each driver and let them decide if
they need lock to write into the GIC.

With this assumption, you won't need your indirection in the ops handler.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-28 12:06       ` Julien Grall
@ 2014-04-28 13:10         ` Vijay Kilari
  2014-04-28 13:12           ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-04-28 13:10 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Mon, Apr 28, 2014 at 5:36 PM, Julien Grall <julien.grall@linaro.org> wrote:
> Hello Vijaya
>
> On 04/28/2014 12:48 PM, Vijay Kilari wrote:
>> On Wed, Apr 16, 2014 at 12:05 AM, Julien Grall <julien.grall@linaro.org> wrote:
>>> Thank you for the patch.
>>>
>>>>      /* Enable routing */
>>>> -    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
>>>> +    gic_hw_ops->gic_irq_ops->enable(desc);
>>>
>>> This is not the right way to use gic_irq_ops. You should directly
>>> assigned this structure to desc->handler.
>>>
>>  I think desc->handler is already filled with ops of below struct
>> which is used
>
> No, with your patch, the desc->handler is filled with ops from the
> generic code. You added an indirection to call the specific ops.
>

Do you mean to move gic_host_irq_type & gic_quest_irq_type
to gic-{2/3}.c and register these with generic driver?
So with this gic_lock should also be moved to gic-{2,3}.c

> In any case, you are only partially define the ops here, which is wrong.
> Every callbacks should be defined for consistency.
>
>> static hw_irq_controller gic_host_irq_type = {
>>     .typename = "gic",
>>     .startup = gic_irq_startup,
>>     .shutdown = gic_irq_shutdown,
>>     .enable = gic_irq_enable,
>>     .disable = gic_irq_disable,
>>     .ack = gic_irq_ack,
>>     .end = gic_host_irq_end,
>>     .set_affinity = gic_irq_set_affinity,
>> };
>>
>>> I guess you don't do it because you have the desc->status and gic_lock
>>> locking which is common.
>>>
>>> IHMO, you have to let the GICv{2,3} drivers handling their own lock for
>>> the hardware access.
>>
>> The existing lock gic_lock protects both generic & hw specific functionality.
>> So I could not see need for another level of locking. Anything specific that
>> you see it is missing?
>
> I don't see why you are saying : "The gic_lock protected generic
> functionality".
> I've looked at the code and the gic.lock is only used to protect call to
> gic callback.
> The gic_lock has been designed to protect access to the hardware, *NOT*
> the internal structure.
>
> IHMO, this lock should be moved in each driver and let them decide if
> they need lock to write into the GIC.
>
> With this assumption, you won't need your indirection in the ops handler.
>
> Regards,
>
> --
> Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-28 13:10         ` Vijay Kilari
@ 2014-04-28 13:12           ` Julien Grall
  0 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-28 13:12 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 04/28/2014 02:10 PM, Vijay Kilari wrote:
> On Mon, Apr 28, 2014 at 5:36 PM, Julien Grall <julien.grall@linaro.org> wrote:
>> Hello Vijaya
>>
>> On 04/28/2014 12:48 PM, Vijay Kilari wrote:
>>> On Wed, Apr 16, 2014 at 12:05 AM, Julien Grall <julien.grall@linaro.org> wrote:
>>>> Thank you for the patch.
>>>>
>>>>>      /* Enable routing */
>>>>> -    GICD[GICD_ISENABLER + irq / 32] = (1u << (irq % 32));
>>>>> +    gic_hw_ops->gic_irq_ops->enable(desc);
>>>>
>>>> This is not the right way to use gic_irq_ops. You should directly
>>>> assigned this structure to desc->handler.
>>>>
>>>  I think desc->handler is already filled with ops of below struct
>>> which is used
>>
>> No, with your patch, the desc->handler is filled with ops from the
>> generic code. You added an indirection to call the specific ops.
>>
> 
> Do you mean to move gic_host_irq_type & gic_quest_irq_type
> to gic-{2/3}.c and register these with generic driver?
> So with this gic_lock should also be moved to gic-{2,3}.c

Yes. As I said in my previous mail, the gic_lock is only used to protect
hardware in your patch. I don't see any good reason to keep it in the
generic code.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-23 14:52   ` Ian Campbell
@ 2014-04-28 14:41     ` Vijay Kilari
  2014-04-28 14:58       ` Ian Campbell
  2014-04-28 15:10       ` Julien Grall
  0 siblings, 2 replies; 107+ messages in thread
From: Vijay Kilari @ 2014-04-28 14:41 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

Hi Ian,

On Wed, Apr 23, 2014 at 8:22 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> GIC driver contains both generic and hardware specific low
>> level functionality in gic.c file.
>>
>> With this patch, low level functionality is moved to separate
>> file gic-v2.c and generic code is kept in gic.c file
>>
>> Callbacks are registered by low level driver with generic driver
>> and are called whereever required.
>>
>> The locking mechanism is now kept in generic code as is and
>> hence it is upto generic driver to take proper locks before
>> calling low level driver callbacks.
>
> Please can you document this no a per hook basis in the definition of
> struct gic_hw_operations.
>
>> This helps to separate generic and hardware functionality
>
>> +static struct gic_hw_operations gic_ops;
>
> Please order the file:
>         callbacks
>         gic_hw_ops struct
>         initialisation functions
>
   With comment from Julien, I have not moved gic lock to generic
code. I checked and found that gic lock is used to lock generic code
at only one place in gic_set_irq_properties which is not need as desc lock
is taken and is enough.

> Then you can avoid the forward reference and hopefully make things
> const.
>
>> +static struct dt_irq * gicv2_maintenance_irq(void)
>> +{
>> +    return &gic.maintenance;
>
> How much does the generic maintenance interrupt handling do? Seems like
> just routing it and requesting it, in which case I wonder if we
> shouldn't just push all the MI stuff down into the specific drivers.
> What do you think?

   With Stefano's patch set, MI handler is dummy. Though we move
this stuff to specific drivers, still we need to have a callback to
generic driver to handler it. Ex; gic_route_ppis() &
init_maintenance_interrupt()
of generic code needs a callback

>
>> +static void gicv2_read_lr(int lr, struct gic_lr *lr_reg)
>> +{
>> +    uint32_t lrv;
>> +
>> +    lrv = GICH[GICH_LR + lr];
>> +    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
>> +    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK;
>> +    lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK;
>> +    lr_reg->state    = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
>> +    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;
>> +    lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;
>
> Please either line up the = or don't, not a mixture.
>
>> +static struct gic_hw_operations gic_ops = {
>
> Can be const I think?
   Could not make it const because, some fields like nr_lrs,
gic_lines, hw_version
needs to be populated at runtime/init code
>
>> +    .secondary_init      = gicv2_secondary_cpu_init,
>> +    .get_maintenance_irq = gicv2_maintenance_irq,
>> +    .save_state          = gicv2_save_state,
>> +    .restore_state       = gicv2_restore_state,
>> +    .dump_state          = gicv2_dump_state,
>> +    .gicv_setup          = gicv_v2_init,
>> +    .gic_irq_ops         = &irq_ops,
>> +    .deactivate_irq      = gicv2_dir_irq,
>> +    .ack_irq             = gicv2_ack_irq,
>> +    .set_irq_property    = gicv2_set_irq_properties,
>> +    .send_sgi            = gicv2_send_sgi,
>> +    .disable_interface   = gicv2_disable_interface,
>> +    .update_lr           = gicv2_update_lr,
>> +    .update_hcr_status   = gicv2_hcr_status,
>> +    .clear_lr            = gicv2_clear_lr,
>> +    .read_lr             = gicv2_read_lr,
>> +    .write_lr            = gicv2_write_lr,
>> +    .read_vmcr_priority  = gicv2_read_vmcr_priority,
>> +};
>> +
>> +/*
>> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
>> index eba41ee..2387e38 100644
>> --- a/xen/include/asm-arm/gic.h
>> +++ b/xen/include/asm-arm/gic.h
>> @@ -43,12 +43,41 @@
>>  #define SGI_TARGET_OTHERS  1
>>  #define SGI_TARGET_SELF    2
>>
>> +#define GICH_LR_PENDING    1
>> +#define GICH_LR_ACTIVE     2
>> +
>> +#define GICH_HCR_EN       (1 << 0)
>> +#define GICH_HCR_UIE      (1 << 1)
>> +#define GICH_HCR_LRENPIE  (1 << 2)
>> +#define GICH_HCR_NPIE     (1 << 3)
>> +#define GICH_HCR_VGRP0EIE (1 << 4)
>> +#define GICH_HCR_VGRP0DIE (1 << 5)
>> +#define GICH_HCR_VGRP1EIE (1 << 6)
>> +#define GICH_HCR_VGRP1DIE (1 << 7)
>
> Didn't you just move all these out of this file in a previous patch?
> Please don't do that.
   In the next version, I plan not to have separate gic header file
for V2 & V3. Instead I move(few) required gic version specific definitions
in c file.

I have made a patch to make gic definitions common across v2 & v3
by removing /4 in gic.h register address definitions. With this,
patched gic driver to use ioremap instead fixmap and updated vgic driver
accordingly

- Vijay

>
> Ian.
>

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-28 14:41     ` Vijay Kilari
@ 2014-04-28 14:58       ` Ian Campbell
  2014-04-28 15:10       ` Julien Grall
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-04-28 14:58 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Mon, 2014-04-28 at 20:11 +0530, Vijay Kilari wrote:
> Hi Ian,
> 
> On Wed, Apr 23, 2014 at 8:22 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> > On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> >>
> >> GIC driver contains both generic and hardware specific low
> >> level functionality in gic.c file.
> >>
> >> With this patch, low level functionality is moved to separate
> >> file gic-v2.c and generic code is kept in gic.c file
> >>
> >> Callbacks are registered by low level driver with generic driver
> >> and are called whereever required.
> >>
> >> The locking mechanism is now kept in generic code as is and
> >> hence it is upto generic driver to take proper locks before
> >> calling low level driver callbacks.
> >
> > Please can you document this no a per hook basis in the definition of
> > struct gic_hw_operations.
> >
> >> This helps to separate generic and hardware functionality
> >
> >> +static struct gic_hw_operations gic_ops;
> >
> > Please order the file:
> >         callbacks
> >         gic_hw_ops struct
> >         initialisation functions
> >
>    With comment from Julien, I have not moved gic lock to generic
> code. I checked and found that gic lock is used to lock generic code
> at only one place in gic_set_irq_properties which is not need as desc lock
> is taken and is enough.

My comment wasn't due to the gic_lock stuff, but rather the forward
declaration of gic_ops which can be avoided and hopefully allow the
declaration to become const.

> >> +static struct dt_irq * gicv2_maintenance_irq(void)
> >> +{
> >> +    return &gic.maintenance;
> >
> > How much does the generic maintenance interrupt handling do? Seems like
> > just routing it and requesting it, in which case I wonder if we
> > shouldn't just push all the MI stuff down into the specific drivers.
> > What do you think?
> 
>    With Stefano's patch set, MI handler is dummy. Though we move
> this stuff to specific drivers, still we need to have a callback to
> generic driver to handler it. Ex; gic_route_ppis() &
> init_maintenance_interrupt()
> of generic code needs a callback
> 
> >
> >> +static void gicv2_read_lr(int lr, struct gic_lr *lr_reg)
> >> +{
> >> +    uint32_t lrv;
> >> +
> >> +    lrv = GICH[GICH_LR + lr];
> >> +    lr_reg->pirq = (lrv >> GICH_LR_PHYSICAL_SHIFT) & GICH_LR_PHYSICAL_MASK;
> >> +    lr_reg->virq = (lrv >> GICH_LR_VIRTUAL_SHIFT) & GICH_LR_VIRTUAL_MASK;
> >> +    lr_reg->priority = (lrv >> GICH_LR_PRIORITY_SHIFT) & GICH_LR_PRIORITY_MASK;
> >> +    lr_reg->state    = (lrv >> GICH_LR_STATE_SHIFT) & GICH_LR_STATE_MASK;
> >> +    lr_reg->hw_status = (lrv >> GICH_LR_HW_SHIFT) & GICH_LR_HW_MASK;
> >> +    lr_reg->grp = (lrv >> GICH_LR_GRP_SHIFT) & GICH_LR_GRP_MASK;
> >
> > Please either line up the = or don't, not a mixture.
> >
> >> +static struct gic_hw_operations gic_ops = {
> >
> > Can be const I think?
>    Could not make it const because, some fields like nr_lrs,
> gic_lines, hw_version
> needs to be populated at runtime/init code

I think this is due to mixing static ops and runtime data. Can we not
separate the static ops into a proper "ops" thing? As it stands gic_ops
is rather misnamed since it contains "instance variables" as well.

> >> +    .secondary_init      = gicv2_secondary_cpu_init,
> >> +    .get_maintenance_irq = gicv2_maintenance_irq,
> >> +    .save_state          = gicv2_save_state,
> >> +    .restore_state       = gicv2_restore_state,
> >> +    .dump_state          = gicv2_dump_state,
> >> +    .gicv_setup          = gicv_v2_init,
> >> +    .gic_irq_ops         = &irq_ops,
> >> +    .deactivate_irq      = gicv2_dir_irq,
> >> +    .ack_irq             = gicv2_ack_irq,
> >> +    .set_irq_property    = gicv2_set_irq_properties,
> >> +    .send_sgi            = gicv2_send_sgi,
> >> +    .disable_interface   = gicv2_disable_interface,
> >> +    .update_lr           = gicv2_update_lr,
> >> +    .update_hcr_status   = gicv2_hcr_status,
> >> +    .clear_lr            = gicv2_clear_lr,
> >> +    .read_lr             = gicv2_read_lr,
> >> +    .write_lr            = gicv2_write_lr,
> >> +    .read_vmcr_priority  = gicv2_read_vmcr_priority,
> >> +};
> >> +
> >> +/*
> >> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> >> index eba41ee..2387e38 100644
> >> --- a/xen/include/asm-arm/gic.h
> >> +++ b/xen/include/asm-arm/gic.h
> >> @@ -43,12 +43,41 @@
> >>  #define SGI_TARGET_OTHERS  1
> >>  #define SGI_TARGET_SELF    2
> >>
> >> +#define GICH_LR_PENDING    1
> >> +#define GICH_LR_ACTIVE     2
> >> +
> >> +#define GICH_HCR_EN       (1 << 0)
> >> +#define GICH_HCR_UIE      (1 << 1)
> >> +#define GICH_HCR_LRENPIE  (1 << 2)
> >> +#define GICH_HCR_NPIE     (1 << 3)
> >> +#define GICH_HCR_VGRP0EIE (1 << 4)
> >> +#define GICH_HCR_VGRP0DIE (1 << 5)
> >> +#define GICH_HCR_VGRP1EIE (1 << 6)
> >> +#define GICH_HCR_VGRP1DIE (1 << 7)
> >
> > Didn't you just move all these out of this file in a previous patch?
> > Please don't do that.
>    In the next version, I plan not to have separate gic header file
> for V2 & V3. Instead I move(few) required gic version specific definitions
> in c file.
> 
> I have made a patch to make gic definitions common across v2 & v3
> by removing /4 in gic.h register address definitions. With this,
> patched gic driver to use ioremap instead fixmap and updated vgic driver
> accordingly

Sounds good. Thanks.

Ian
> 
> - Vijay
> 
> >
> > Ian.
> >

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality
  2014-04-28 14:41     ` Vijay Kilari
  2014-04-28 14:58       ` Ian Campbell
@ 2014-04-28 15:10       ` Julien Grall
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-28 15:10 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 04/28/2014 03:41 PM, Vijay Kilari wrote:
>    With Stefano's patch set, MI handler is dummy. Though we move
> this stuff to specific drivers, still we need to have a callback to
> generic driver to handler it. Ex; gic_route_ppis() &
> init_maintenance_interrupt()
> of generic code needs a callback

gic_route_ppis has been removed with my interrupt series (see
http://www.gossamer-threads.com/lists/xen/devel/326620).
It also rework gic_set_irq_properties by taking the gic.lock directly in
the function.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 09/16] xen/arm: use device api to detect GIC version
  2014-04-23 15:01   ` Ian Campbell
@ 2014-04-29  7:07     ` Vijay Kilari
  2014-04-29  8:55       ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-04-29  7:07 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Wed, Apr 23, 2014 at 8:31 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
>> +static const char * const gicv2_dt_compat[] __initconst =
>> +{
>> +    "arm,cortex-a15-gic",
>> +    "arm,cortex-a9-gic",
>
> This is DT_MATCH_GIC. Please keep using it. Perhaps you will want to
> rename it to DT_MATCH_GICV2.
>
DT_MATCH_GIC is redefined as DT_MATCH_COMPATIBLE, so could not
use it here.
#define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
                        DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 09/16] xen/arm: use device api to detect GIC version
  2014-04-29  7:07     ` Vijay Kilari
@ 2014-04-29  8:55       ` Ian Campbell
  2014-04-29 10:13         ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-04-29  8:55 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Tue, 2014-04-29 at 12:37 +0530, Vijay Kilari wrote:
> On Wed, Apr 23, 2014 at 8:31 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> > On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> >> +static const char * const gicv2_dt_compat[] __initconst =
> >> +{
> >> +    "arm,cortex-a15-gic",
> >> +    "arm,cortex-a9-gic",
> >
> > This is DT_MATCH_GIC. Please keep using it. Perhaps you will want to
> > rename it to DT_MATCH_GICV2.
> >
> DT_MATCH_GIC is redefined as DT_MATCH_COMPATIBLE, so could not
> use it here.
> #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
>                         DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")

Hrm I thought you were removing the existing use of DT_MATCH_GIC so you
could change it, but actually one remains.

A little unsatisfactory to have this list twice. Not sure what to do. At
the least we could define DT_MATCH_GIC_COMPATIBLE and
DT_MATCH_GIC_STRING next to each other in the same header.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 09/16] xen/arm: use device api to detect GIC version
  2014-04-29  8:55       ` Ian Campbell
@ 2014-04-29 10:13         ` Julien Grall
  0 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-04-29 10:13 UTC (permalink / raw)
  To: Ian Campbell, Vijay Kilari
  Cc: Prasun Kapoor, Vijaya Kumar K, xen-devel, Stefano Stabellini,
	Stefano Stabellini



On 29/04/14 09:55, Ian Campbell wrote:
> On Tue, 2014-04-29 at 12:37 +0530, Vijay Kilari wrote:
>> On Wed, Apr 23, 2014 at 8:31 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
>>> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
>>>> +static const char * const gicv2_dt_compat[] __initconst =
>>>> +{
>>>> +    "arm,cortex-a15-gic",
>>>> +    "arm,cortex-a9-gic",
>>>
>>> This is DT_MATCH_GIC. Please keep using it. Perhaps you will want to
>>> rename it to DT_MATCH_GICV2.
>>>
>> DT_MATCH_GIC is redefined as DT_MATCH_COMPATIBLE, so could not
>> use it here.
>> #define DT_MATCH_GIC    DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), \
>>                          DT_MATCH_COMPATIBLE("arm,cortex-a7-gic")
>
> Hrm I thought you were removing the existing use of DT_MATCH_GIC so you
> could change it, but actually one remains.
>
> A little unsatisfactory to have this list twice. Not sure what to do. At
> the least we could define DT_MATCH_GIC_COMPATIBLE and
> DT_MATCH_GIC_STRING next to each other in the same header.

We could also extend/modify the device API to accept DT_MATCH* instead 
of a list of compatible string.

I don't really like this solution but it will avoid to have 2 times the 
same list of compatible string with only minor changes.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-23 17:24     ` Julien Grall
@ 2014-04-29 12:35       ` Vijay Kilari
  0 siblings, 0 replies; 107+ messages in thread
From: Vijay Kilari @ 2014-04-29 12:35 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Wed, Apr 23, 2014 at 10:54 PM, Julien Grall <julien.grall@linaro.org> wrote:
> On 04/23/2014 06:01 PM, Ian Campbell wrote:
>>> +    } while ( count-- );
>>> +
>>> +    if ( !count )
>>> +        dprintk(XENLOG_WARNING, "RWP timeout\n");
>>
>> Shouldn't we panic here?
>
> I don't think panic is the solution here. This might be use on secondary
> CPU.
>
> IHMO, we should return an error code here an handle here upper in the
> call stack.
>
>>> +static void gicv3_restore_state(struct vcpu *v)
>>> +{
>>> +    int i;
>>> +
>>> +    for ( i = 0; i < nr_lrs; i++)
>>> +        gich_write_lr(i, v->arch.gic.v3.lr[i]);
>>
>> I wonder if the compiler could do a better job of this using the same
>> switch and fallthrough method you used for aprn regs?
>
> Marc has written a very nice solution for this stuff. It as written an
> assembly function where all registers is save decreasing the number.
>
> When the function, it will calculate the number of regs we don't need of
> LRs save. This will avoid lots of jumps.
>
> See code below (see http://permalink.gmane.org
> /gmane.linux.ports.arm.kernel/310855 for the whole patch):
>
> +       sub     w23, w23, w22   // How many regs we have to skip
> +
> +       adr     x24, 1f
> +       add     x24, x24, x23, lsl #2
> +       br      x24
> +
> +1:
> +       mrs     x20, ICH_LR15_EL2
> +       mrs     x19, ICH_LR14_EL2
> +       mrs     x18, ICH_LR13_EL2
> +       mrs     x17, ICH_LR12_EL2
> +       mrs     x16, ICH_LR11_EL2
> +       mrs     x15, ICH_LR10_EL2
> +       mrs     x14, ICH_LR9_EL2
> +       mrs     x13, ICH_LR8_EL2
> +       mrs     x12, ICH_LR7_EL2
> +       mrs     x11, ICH_LR6_EL2
> +       mrs     x10, ICH_LR5_EL2
> +       mrs     x9, ICH_LR4_EL2
> +       mrs     x8, ICH_LR3_EL2
> +       mrs     x7, ICH_LR2_EL2
> +       mrs     x6, ICH_LR1_EL2
> +       mrs     x5, ICH_LR0_EL2
> +
>
 Instead of having assembly function for store & restore of LR's
How about having one function that stores & restores all 15 LR's
without any checks using READ_SYSREG/WRITE_SYSREG macro's?

For reading specific LR we can use existing switch case function?

> [..]
>
>>> +                return 0;
>>
>> So basically we only know the number of redistributors from device tree
>> and not the mapping from RDIST to CPU, so we have to try every one?
>>
>> Do you have a reference to the GIC v3 Device Tree bindings? I don't see
>> them in linux/Documentation/devicetree/bindings/.
>
> GICv3 is not upstream for now. Marc as sent the V3 recently:
>
> http://comments.gmane.org/gmane.linux.ports.arm.kernel/316902
>
> --
> Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 14/16] xen/arm: Add virtual GICv3 support
  2014-04-24 10:30   ` Ian Campbell
@ 2014-05-02  9:43     ` Vijay Kilari
  2014-05-02  9:56       ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-05-02  9:43 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Thu, Apr 24, 2014 at 4:00 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> Add virtual GICv3 driver support
>>
>> This patch adds only basic v3 support.
>> Does not support Interrupt Translation support (ITS)
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>> +/*
>> + * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
>> + * <b>-bits-per-interrupt.
>> + */
>> +/* Shift n >> 2 to make it byte register diff */
>
> These two comments should be merged.
>
> What is a "byte register diff"? Do you mean offset in bytes?
>
> The shift still confuses me, even with the comment. Isn't it shifting
> the wrong way to convert something to bytes?
>
>> +#define REG_RANK_INDEX(b, n) (((n) >> 2) & ((b)-1))
>> +
>> +/*
>> + * Returns rank corresponding to a GICD_<FOO><n> register for
>> + * GICD_<FOO> with <b>-bits-per-interrupt.
>> + */
>> +static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
>> +{
>> +    int rank;
>> +
>> +    /* divide by 4 to make it byte size register difference
>> +      as n is difference of 4 byte size register */
>> +    n = n >> 2;
>
> I'm confused again by this comment, if the input n is at word
> granularity why divide and not multiple to get bytes? Or maybe the
> comment is backwards and you have bytes and want a word sized offset?
>
   When REG_RANK_INDEX is called, this macro assumes
that the n value is difference of register in bytes to compute rank

Ex: In old implementation of vgic, the register definitions are divided / 4
So when REG_RANK_INDEX is called, then n value is (x/4 -  y/4)

In the same case in GICv3 I defined all the register definitions are not
divided /4 . Hence n value is x - y which is always multiples of 4.
So I right shifted n by 2 to get the right rank index

In GICv3 there are some register which are 8 bytes (64 bit) for
those I right shift by 3.

>> +        goto read_as_zero;
>> +    case GICR_SETLPIR:
>> +    case GICR_CLRLPIR:
>> +        /* WO return fail */
>> +        return 0;
>
> What is the defined/expected hardware behaviour if you read this
> register? Read garbage or trap?
  Write on RO register is read as zero and Write on RO is write ignored

>
>> +static int vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info)
>> +{
>> +    uint32_t offset;
>> +
>> +    if ( !v->domain->arch.vgic.rdist_stride )
>> +        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
>> +    else
>> +        offset = info->gpa & 0x1FFFF;
>
> Please initialiase rdist_stride to a default which would cause this same
> behaviour when it is not explicit and avoid the conditional here.

   The rdist_stride value is the value that is received from dt.
   So I have not changed the value

>> +    case REG(0x00c):
>> +    case REG(0x044):
>> +    case REG(0x04c):
>> +    case REG(0x05c) ... REG(0x07c):
>> +    case REG(0xf30) ... REG(0x5fcc):
>> +    case REG(0x8000) ... REG(0xbfcc):
>> +    case REG(0xc000) ... REG(0xffcc):
>
> What distinguishes these registers from those captured by the default
> clause? Are these unimplemented implementation defined registers? Is
> there a reason to expect a guest to legitimately prod them?

   This is no way different from default. These are reserved register addresses.
    Just retained similar to vgic.c (v2).

>> +    for ( i = 0; i < d->arch.vgic.rdist_count; i++ )
>> +    {
>> +        vgic_rdistr_mmio_handler.addr = d->arch.vgic.rbase[i];
>> +        vgic_rdistr_mmio_handler.size = d->arch.vgic.rbase_size[i];
>> +        register_mmio_handler(d, &vgic_rdistr_mmio_handler);
>
> Can we processes the rdistr stride here (or when we setup
> d->arch.vgic.rbase*) and register the sgi region separately?

   sgi region is per core. So we have to register for every core.
   But handling is same for all. So one handler is good enough

-Vijay

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 14/16] xen/arm: Add virtual GICv3 support
  2014-05-02  9:43     ` Vijay Kilari
@ 2014-05-02  9:56       ` Ian Campbell
  0 siblings, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-05-02  9:56 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Fri, 2014-05-02 at 15:13 +0530, Vijay Kilari wrote:
> >> +#define REG_RANK_INDEX(b, n) (((n) >> 2) & ((b)-1))
> >> +
> >> +/*
> >> + * Returns rank corresponding to a GICD_<FOO><n> register for
> >> + * GICD_<FOO> with <b>-bits-per-interrupt.
> >> + */
> >> +static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
> >> +{
> >> +    int rank;
> >> +
> >> +    /* divide by 4 to make it byte size register difference
> >> +      as n is difference of 4 byte size register */
> >> +    n = n >> 2;
> >
> > I'm confused again by this comment, if the input n is at word
> > granularity why divide and not multiple to get bytes? Or maybe the
> > comment is backwards and you have bytes and want a word sized offset?
> >
>    When REG_RANK_INDEX is called, this macro assumes
> that the n value is difference of register in bytes to compute rank
> 
> Ex: In old implementation of vgic, the register definitions are divided / 4
> So when REG_RANK_INDEX is called, then n value is (x/4 -  y/4)
> 
> In the same case in GICv3 I defined all the register definitions are not
> divided /4 . Hence n value is x - y which is always multiples of 4.
> So I right shifted n by 2 to get the right rank index

Then the comment is confusing and/or backwards. It says "device by 4 to
make it byte size", but you just said it was already byte size and you
were converting it into a word sized.

> 
> In GICv3 there are some register which are 8 bytes (64 bit) for
> those I right shift by 3.
> 
> >> +        goto read_as_zero;
> >> +    case GICR_SETLPIR:
> >> +    case GICR_CLRLPIR:
> >> +        /* WO return fail */
> >> +        return 0;
> >
> > What is the defined/expected hardware behaviour if you read this
> > register? Read garbage or trap?

>   Write on RO register is read as zero and Write on RO is write ignored

You haven't done either though, you've made it send a trap to the guest.

> >> +static int vgic_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info)
> >> +{
> >> +    uint32_t offset;
> >> +
> >> +    if ( !v->domain->arch.vgic.rdist_stride )
> >> +        offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
> >> +    else
> >> +        offset = info->gpa & 0x1FFFF;
> >
> > Please initialiase rdist_stride to a default which would cause this same
> > behaviour when it is not explicit and avoid the conditional here.
> 
>    The rdist_stride value is the value that is received from dt.
>    So I have not changed the value

I understood this, it is wrong, I was explicitly asking for it to be
changed.

rdist_stride should be the rdist_stride, whether it is derived from the
DT, calculated some other way or magicked out of the air. The only place
where any of that matters should be done is point where rdist_stride is
set, not at every use.


> 
> >> +    case REG(0x00c):
> >> +    case REG(0x044):
> >> +    case REG(0x04c):
> >> +    case REG(0x05c) ... REG(0x07c):
> >> +    case REG(0xf30) ... REG(0x5fcc):
> >> +    case REG(0x8000) ... REG(0xbfcc):
> >> +    case REG(0xc000) ... REG(0xffcc):
> >
> > What distinguishes these registers from those captured by the default
> > clause? Are these unimplemented implementation defined registers? Is
> > there a reason to expect a guest to legitimately prod them?
> 
>    This is no way different from default. These are reserved register addresses.
>     Just retained similar to vgic.c (v2).

In v2 there is a comment explaining what these are and why they are
special.

> 
> >> +    for ( i = 0; i < d->arch.vgic.rdist_count; i++ )
> >> +    {
> >> +        vgic_rdistr_mmio_handler.addr = d->arch.vgic.rbase[i];
> >> +        vgic_rdistr_mmio_handler.size = d->arch.vgic.rbase_size[i];
> >> +        register_mmio_handler(d, &vgic_rdistr_mmio_handler);
> >
> > Can we processes the rdistr stride here (or when we setup
> > d->arch.vgic.rbase*) and register the sgi region separately?
> 
>    sgi region is per core. So we have to register for every core.
>    But handling is same for all. So one handler is good enough

Please add a comment to explain this then.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-04-18 20:20   ` Julien Grall
@ 2014-05-02 12:57     ` Vijay Kilari
  2014-05-02 14:26       ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-05-02 12:57 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Sat, Apr 19, 2014 at 1:50 AM, Julien Grall <julien.grall@linaro.org> wrote:
> Hello Vijaya,
>
>
> On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
>>
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
>> Handle the trap and inject SGI to vcpu.
>>
>>   /* The base of the stack must always be double-word aligned, which means
>>    * that both the kernel half of struct cpu_user_regs (which is pushed in
>> @@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
>>               domain_crash_synchronous();
>>           }
>>           break;
>> +    case HSR_SYSREG_ICC_SGI1R_EL1:
>
>
> Any reason to not trap ICC_SGI0R_EL1 and ICC_ASGI1R_EL1?

Does Xen supports Secure guests?. In any case, I can make a check on GICR_NSACR
and reject if generating non-secure writes are permitted to generate
secure grp0 interrupts.
Similarly for ICC_ASG1R_EL1.
>
>
>> +        if ( !vgic_emulate(regs, hsr) )
>> +        {
>> +            dprintk(XENLOG_ERR,
>> +                    "failed emulation of 64-bit vgic sysreg access\n");
>> +            domain_crash_synchronous();
>
>
> So, you crash the domain if the SGI is not handled??? The GICv3 spec
> requests a specific behavior.

   Can you please point to GICv3 spec that request specific behavior
to handle this scenario?

-Vijay

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-02 12:57     ` Vijay Kilari
@ 2014-05-02 14:26       ` Julien Grall
  2014-05-02 15:18         ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-05-02 14:26 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 05/02/2014 01:57 PM, Vijay Kilari wrote:
> On Sat, Apr 19, 2014 at 1:50 AM, Julien Grall <julien.grall@linaro.org> wrote:
>> Hello Vijaya,
>>
>>
>> On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
>>>
>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>
>>> In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
>>> Handle the trap and inject SGI to vcpu.
>>>
>>>   /* The base of the stack must always be double-word aligned, which means
>>>    * that both the kernel half of struct cpu_user_regs (which is pushed in
>>> @@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
>>>               domain_crash_synchronous();
>>>           }
>>>           break;
>>> +    case HSR_SYSREG_ICC_SGI1R_EL1:
>>
>>
>> Any reason to not trap ICC_SGI0R_EL1 and ICC_ASGI1R_EL1?
> 
> Does Xen supports Secure guests?. In any case, I can make a check on GICR_NSACR
> and reject if generating non-secure writes are permitted to generate
> secure grp0 interrupts.
> Similarly for ICC_ASG1R_EL1.

It's not possible to have secure guest. Are you sure it will never trap
to Xen if the guest try to generate a Group 1 SGIs to a secure state?
(see ICC_ASGI1R_EL1).

>>
>>
>>> +        if ( !vgic_emulate(regs, hsr) )
>>> +        {
>>> +            dprintk(XENLOG_ERR,
>>> +                    "failed emulation of 64-bit vgic sysreg access\n");
>>> +            domain_crash_synchronous();
>>
>>
>> So, you crash the domain if the SGI is not handled??? The GICv3 spec
>> requests a specific behavior.
> 
>    Can you please point to GICv3 spec that request specific behavior
> to handle this scenario?

6.5.1: "Read-Only and Write-Only System Register Accesses"

You should inject an UNDEF exception.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-02 14:26       ` Julien Grall
@ 2014-05-02 15:18         ` Ian Campbell
  2014-05-02 15:24           ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-05-02 15:18 UTC (permalink / raw)
  To: Julien Grall
  Cc: Vijay Kilari, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Fri, 2014-05-02 at 15:26 +0100, Julien Grall wrote:
> On 05/02/2014 01:57 PM, Vijay Kilari wrote:
> > On Sat, Apr 19, 2014 at 1:50 AM, Julien Grall <julien.grall@linaro.org> wrote:
> >> Hello Vijaya,
> >>
> >>
> >> On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
> >>>
> >>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> >>>
> >>> In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
> >>> Handle the trap and inject SGI to vcpu.
> >>>
> >>>   /* The base of the stack must always be double-word aligned, which means
> >>>    * that both the kernel half of struct cpu_user_regs (which is pushed in
> >>> @@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
> >>>               domain_crash_synchronous();
> >>>           }
> >>>           break;
> >>> +    case HSR_SYSREG_ICC_SGI1R_EL1:
> >>
> >>
> >> Any reason to not trap ICC_SGI0R_EL1 and ICC_ASGI1R_EL1?
> > 
> > Does Xen supports Secure guests?. In any case, I can make a check on GICR_NSACR
> > and reject if generating non-secure writes are permitted to generate
> > secure grp0 interrupts.
> > Similarly for ICC_ASG1R_EL1.
> 
> It's not possible to have secure guest. Are you sure it will never trap
> to Xen if the guest try to generate a Group 1 SGIs to a secure state?
> (see ICC_ASGI1R_EL1).

Wouldn't the correct response be to crash a guest who tried?

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-02 15:18         ` Ian Campbell
@ 2014-05-02 15:24           ` Julien Grall
  2014-05-05  6:53             ` Vijay Kilari
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-05-02 15:24 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Vijay Kilari, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 05/02/2014 04:18 PM, Ian Campbell wrote:
> On Fri, 2014-05-02 at 15:26 +0100, Julien Grall wrote:
>> On 05/02/2014 01:57 PM, Vijay Kilari wrote:
>>> On Sat, Apr 19, 2014 at 1:50 AM, Julien Grall <julien.grall@linaro.org> wrote:
>>>> Hello Vijaya,
>>>>
>>>>
>>>> On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
>>>>>
>>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>>
>>>>> In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
>>>>> Handle the trap and inject SGI to vcpu.
>>>>>
>>>>>   /* The base of the stack must always be double-word aligned, which means
>>>>>    * that both the kernel half of struct cpu_user_regs (which is pushed in
>>>>> @@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
>>>>>               domain_crash_synchronous();
>>>>>           }
>>>>>           break;
>>>>> +    case HSR_SYSREG_ICC_SGI1R_EL1:
>>>>
>>>>
>>>> Any reason to not trap ICC_SGI0R_EL1 and ICC_ASGI1R_EL1?
>>>
>>> Does Xen supports Secure guests?. In any case, I can make a check on GICR_NSACR
>>> and reject if generating non-secure writes are permitted to generate
>>> secure grp0 interrupts.
>>> Similarly for ICC_ASG1R_EL1.
>>
>> It's not possible to have secure guest. Are you sure it will never trap
>> to Xen if the guest try to generate a Group 1 SGIs to a secure state?
>> (see ICC_ASGI1R_EL1).
> 
> Wouldn't the correct response be to crash a guest who tried?

The GICv3 spec requests to send a UNDEF exception if the register is not
implemented.

In general way, I think UNDEF is a best solution as some kernel such as
Linux is able to recover from an undef on some specific access (it's
actually the case for some debug registers on ARM32).

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-02 15:24           ` Julien Grall
@ 2014-05-05  6:53             ` Vijay Kilari
  2014-05-05 18:40               ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-05-05  6:53 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Fri, May 2, 2014 at 8:54 PM, Julien Grall <julien.grall@linaro.org> wrote:
> On 05/02/2014 04:18 PM, Ian Campbell wrote:
>> On Fri, 2014-05-02 at 15:26 +0100, Julien Grall wrote:
>>> On 05/02/2014 01:57 PM, Vijay Kilari wrote:
>>>> On Sat, Apr 19, 2014 at 1:50 AM, Julien Grall <julien.grall@linaro.org> wrote:
>>>>> Hello Vijaya,
>>>>>
>>>>>
>>>>> On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
>>>>>>
>>>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>>>
>>>>>> In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
>>>>>> Handle the trap and inject SGI to vcpu.
>>>>>>
>>>>>>   /* The base of the stack must always be double-word aligned, which means
>>>>>>    * that both the kernel half of struct cpu_user_regs (which is pushed in
>>>>>> @@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
>>>>>>               domain_crash_synchronous();
>>>>>>           }
>>>>>>           break;
>>>>>> +    case HSR_SYSREG_ICC_SGI1R_EL1:
>>>>>
>>>>>
>>>>> Any reason to not trap ICC_SGI0R_EL1 and ICC_ASGI1R_EL1?
>>>>
>>>> Does Xen supports Secure guests?. In any case, I can make a check on GICR_NSACR
>>>> and reject if generating non-secure writes are permitted to generate
>>>> secure grp0 interrupts.
>>>> Similarly for ICC_ASG1R_EL1.
>>>
>>> It's not possible to have secure guest. Are you sure it will never trap
>>> to Xen if the guest try to generate a Group 1 SGIs to a secure state?
>>> (see ICC_ASGI1R_EL1).
>>
>> Wouldn't the correct response be to crash a guest who tried?

As per Spec if ICH_HCR_EL2_TC = 1, virtual access to
ICC_SGI0R_EL1/ICC_SGI1R_EL1/
ICC_ASGI1R_EL1 generate trap.

As per table 29 of GICv3 spec, non-secure EL1/EL2 can access all the
above three registers.
However only write to ICC_SGI1R_EL1 by non-secure EL1/EL2 forwards
non-secure grp 1 interrupt.
All the register access handles Secure Group 0& 1 interrupts.

For now I will just return 1 (UNDEF) with warning for register access
ICC_SGI0R_EL1/
ICC_ASGI1R_EL1. Even if I implement, I have no SW environment to test
secure interrupt handling for now

>
> The GICv3 spec requests to send a UNDEF exception if the register is not
> implemented.
>
> In general way, I think UNDEF is a best solution as some kernel such as
> Linux is able to recover from an undef on some specific access (it's
> actually the case for some debug registers on ARM32).

In my understanding, calling inject_undef64_exception() will generate
UNDEF to guest.

>
> Regards,
>
> --
> Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-23 17:01   ` Ian Campbell
  2014-04-23 17:24     ` Julien Grall
@ 2014-05-05 12:08     ` Vijay Kilari
  2014-05-06  8:55       ` Ian Campbell
  2014-05-27 18:17     ` Julien Grall
  2 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-05-05 12:08 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Wed, Apr 23, 2014 at 10:31 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
>

>> +
>> +/* per-cpu re-distributor base */
>> +static DEFINE_PER_CPU(void __iomem*, rbase);
>
> Does this end up containing one of the gic.rdist_regions[i].map entries?
> Any reason to duplicate this in that map field as well? Can't each
> processor map it as it is initialised and store it here directly?
>
> I suppose we have plenty of ioremap space on v8, so nr_cpus*2*64k isn't
> too bad and there's no need to go for per-pcpu pagetables with a
> dedicated virtual address region for the redistributors.
>
Already complete redistributor region is mapped. Here we are just storing
the re-distributor base of each cpu to access GICR SGI region of per cpu.

>> +/* Wait for completion of a distributor change */
>> +static void gicv3_do_wait_for_rwp(void __iomem *base)
>> +{
>> +    u32 val;
>> +    u32 count = 1000000;
>> +
>> +    do {
>> +        val = readl_relaxed(base + GICD_CTLR);
>> +        if ( !(val & GICD_CTLR_RWP) )
>> +           break;
>> +        cpu_relax();
>> +        udelay(1);
>
> Ick. Is there no event when rwp changes, so we could do wfe here?
>
> Could we at least use NOW() and MILLISECS() to construct a delay of a
> known length?

   Do you mean, to use timer handler?. I thought this is simple enough
[...]
>
>> +    } while ( count-- );
>> +
>> +    if ( !count )
>> +        dprintk(XENLOG_WARNING, "RWP timeout\n");
>
> Shouldn't we panic here?
>
> And if we are going to panic, we might as well wait forever? (Perhaps
> with a warning after some number of iterations.
>
    Already after 1sec there is warning. I think warning is enough here
this is not such a critical scenario

[...]

>> +static u16 gicv3_compute_target_list(int *base_cpu, const struct cpumask *mask,
>> +                                   u64 cluster_id)
>> +{
>> +    int cpu = *base_cpu;
>> +    u64 mpidr = cpu_logical_map(cpu);
>> +    u16 tlist = 0;
>> +
>> +    while ( cpu < nr_cpu_ids )
>> +    {
>> +        /*
>> +         * If we ever get a cluster of more than 16 CPUs, just
>> +         * scream and skip that CPU.
>> +         */
>> +        if ( (mpidr & 0xff) >= 16 )
>> +        {
>> +            dprintk(XENLOG_WARNING, "Cluster more than 16's cpus\n");
>> +            goto out;
>> +        }
>> +        tlist |= 1 << (mpidr & 0xf);
>> +
>> +        cpu = cpumask_next(cpu, mask);
>
> Aren't you essentially opencoding for_each_cpu with this check and the
> while loop?
>
> The caller of this function already has a for_each_cpu in it. Can you
> explain the algorithm please.

   Though the caller of this function calls for_each_cpu(), this gicv3_compute_
target_list() will update the *base_cpu always to the first cpu in the cluster
So essentially this for_each_cpu() will loop once per cluster

>
>> +        if ( cpu == nr_cpu_ids )
>> +        {
>> +            cpu--;
>> +            goto out;
>> +        }
>> +
>> +        mpidr = cpu_logical_map(cpu);
>> +        if ( cluster_id != (mpidr & ~0xffUL) ) {
>> +            cpu--;
>> +            goto out;
>> +        }
>> +    }
>> +out:
>> +    *base_cpu = cpu;
>> +    return tlist;
>> +}
>> +
>> +    dsb();
>
> The dsb() macro needs a scope parameter for a while now. Which version
> of Xen is all this based on?

  Based on Stefano's git where your scope parameter patch does not exist

[..]

>> +int gicv_v3_init(struct domain *d)
>> +{
>> +    int i;
>> +    /*
>> +     * Domain 0 gets the hardware address.
>> +     * Guests get the virtual platform layout.
>> +     */
>> +    if ( d->domain_id == 0 )
>> +    {
>> +        d->arch.vgic.dbase = gic.dbase;
>> +        d->arch.vgic.dbase_size = gic.dbase_size;
>> +        for ( i = 0; i < gic.rdist_count; i++ )
>> +        {
>> +            d->arch.vgic.rbase[i] = gic.rdist_regions[i].rdist_base;
>> +            d->arch.vgic.rbase_size[i] = gic.rdist_regions[i].rdist_base_size;
>> +        }
>> +        d->arch.vgic.rdist_stride = gic.rdist_stride;
>> +        d->arch.vgic.rdist_count = gic.rdist_count;
>> +    }
>> +    else
>> +    {
>
> Does this need a comment like "Currently guests see a GICv2"? Otherwise
> doesn't it need an rbase etc?

    Yes, will update it once I test DomU booting

- Vijay

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-05  6:53             ` Vijay Kilari
@ 2014-05-05 18:40               ` Julien Grall
  2014-05-06  8:58                 ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-05-05 18:40 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

Hi Vijay,

On 05/05/14 07:53, Vijay Kilari wrote:
> On Fri, May 2, 2014 at 8:54 PM, Julien Grall <julien.grall@linaro.org> wrote:
>> On 05/02/2014 04:18 PM, Ian Campbell wrote:
>>> On Fri, 2014-05-02 at 15:26 +0100, Julien Grall wrote:
>>>> On 05/02/2014 01:57 PM, Vijay Kilari wrote:
>>>>> On Sat, Apr 19, 2014 at 1:50 AM, Julien Grall <julien.grall@linaro.org> wrote:
>>>>>> Hello Vijaya,
>>>>>>
>>>>>>
>>>>>> On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
>>>>>>>
>>>>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>>>>
>>>>>>> In ARMv8, write to ICC_SGI1R_EL1 register raises trap to EL2.
>>>>>>> Handle the trap and inject SGI to vcpu.
>>>>>>>
>>>>>>>    /* The base of the stack must always be double-word aligned, which means
>>>>>>>     * that both the kernel half of struct cpu_user_regs (which is pushed in
>>>>>>> @@ -1406,6 +1407,14 @@ static void do_sysreg(struct cpu_user_regs *regs,
>>>>>>>                domain_crash_synchronous();
>>>>>>>            }
>>>>>>>            break;
>>>>>>> +    case HSR_SYSREG_ICC_SGI1R_EL1:
>>>>>>
>>>>>>
>>>>>> Any reason to not trap ICC_SGI0R_EL1 and ICC_ASGI1R_EL1?
>>>>>
>>>>> Does Xen supports Secure guests?. In any case, I can make a check on GICR_NSACR
>>>>> and reject if generating non-secure writes are permitted to generate
>>>>> secure grp0 interrupts.
>>>>> Similarly for ICC_ASG1R_EL1.
>>>>
>>>> It's not possible to have secure guest. Are you sure it will never trap
>>>> to Xen if the guest try to generate a Group 1 SGIs to a secure state?
>>>> (see ICC_ASGI1R_EL1).
>>>
>>> Wouldn't the correct response be to crash a guest who tried?
>
> As per Spec if ICH_HCR_EL2_TC = 1, virtual access to
> ICC_SGI0R_EL1/ICC_SGI1R_EL1/
> ICC_ASGI1R_EL1 generate trap.
>
> As per table 29 of GICv3 spec, non-secure EL1/EL2 can access all the
> above three registers.
> However only write to ICC_SGI1R_EL1 by non-secure EL1/EL2 forwards
> non-secure grp 1 interrupt.
> All the register access handles Secure Group 0& 1 interrupts.
>
> For now I will just return 1 (UNDEF) with warning for register access
> ICC_SGI0R_EL1/
> ICC_ASGI1R_EL1. Even if I implement, I have no SW environment to test
> secure interrupt handling for now

As secure interrupt should not happen from the guest. You can check that 
we correctly trap the access to thoses interrupts.

>
>>
>> The GICv3 spec requests to send a UNDEF exception if the register is not
>> implemented.
>>
>> In general way, I think UNDEF is a best solution as some kernel such as
>> Linux is able to recover from an undef on some specific access (it's
>> actually the case for some debug registers on ARM32).
>
> In my understanding, calling inject_undef64_exception() will generate
> UNDEF to guest.

Right. You have to call this function only if the domain is arm aarch64 
guest.

AFAIU, it's possible to have GICv3 support when the guest is armv8 32 
bit. So you will have to call inject_undef32_exception for this case.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-05 12:08     ` Vijay Kilari
@ 2014-05-06  8:55       ` Ian Campbell
  2014-05-06 14:11         ` Vijay Kilari
  0 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-05-06  8:55 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Mon, 2014-05-05 at 17:38 +0530, Vijay Kilari wrote:
> >> +/* Wait for completion of a distributor change */
> >> +static void gicv3_do_wait_for_rwp(void __iomem *base)
> >> +{
> >> +    u32 val;
> >> +    u32 count = 1000000;
> >> +
> >> +    do {
> >> +        val = readl_relaxed(base + GICD_CTLR);
> >> +        if ( !(val & GICD_CTLR_RWP) )
> >> +           break;
> >> +        cpu_relax();
> >> +        udelay(1);
> >
> > Ick. Is there no event when rwp changes, so we could do wfe here?
> >
> > Could we at least use NOW() and MILLISECS() to construct a delay of a
> > known length?
> 
>    Do you mean, to use timer handler?. I thought this is simple enough

No, just
	deadline = NOW() + MILLISECS(somenumber);
	do { 
		val = ...
		if ( )
			break
		if ( NOW() > deadline )
			/* Timeout!
		cpu_relax(), delay etc.
	}


> [...]
> >
> >> +    } while ( count-- );
> >> +
> >> +    if ( !count )
> >> +        dprintk(XENLOG_WARNING, "RWP timeout\n");
> >
> > Shouldn't we panic here?
> >
> > And if we are going to panic, we might as well wait forever? (Perhaps
> > with a warning after some number of iterations.
> >
>     Already after 1sec there is warning. I think warning is enough here
> this is not such a critical scenario

RWP timeout isn't critical? How does it get recovered?

> 
> [...]
> 
> >> +static u16 gicv3_compute_target_list(int *base_cpu, const struct cpumask *mask,
> >> +                                   u64 cluster_id)
> >> +{
> >> +    int cpu = *base_cpu;
> >> +    u64 mpidr = cpu_logical_map(cpu);
> >> +    u16 tlist = 0;
> >> +
> >> +    while ( cpu < nr_cpu_ids )
> >> +    {
> >> +        /*
> >> +         * If we ever get a cluster of more than 16 CPUs, just
> >> +         * scream and skip that CPU.
> >> +         */
> >> +        if ( (mpidr & 0xff) >= 16 )
> >> +        {
> >> +            dprintk(XENLOG_WARNING, "Cluster more than 16's cpus\n");
> >> +            goto out;
> >> +        }
> >> +        tlist |= 1 << (mpidr & 0xf);
> >> +
> >> +        cpu = cpumask_next(cpu, mask);
> >
> > Aren't you essentially opencoding for_each_cpu with this check and the
> > while loop?
> >
> > The caller of this function already has a for_each_cpu in it. Can you
> > explain the algorithm please.
> 
>    Though the caller of this function calls for_each_cpu(), this gicv3_compute_
> target_list() will update the *base_cpu always to the first cpu in the cluster
> So essentially this for_each_cpu() will loop once per cluster
> 
> >
> >> +        if ( cpu == nr_cpu_ids )
> >> +        {
> >> +            cpu--;
> >> +            goto out;
> >> +        }
> >> +
> >> +        mpidr = cpu_logical_map(cpu);
> >> +        if ( cluster_id != (mpidr & ~0xffUL) ) {
> >> +            cpu--;
> >> +            goto out;
> >> +        }
> >> +    }
> >> +out:
> >> +    *base_cpu = cpu;
> >> +    return tlist;
> >> +}
> >> +
> >> +    dsb();
> >
> > The dsb() macro needs a scope parameter for a while now. Which version
> > of Xen is all this based on?
> 
>   Based on Stefano's git where your scope parameter patch does not exist

Stefano's git has dozens of branches in it. This series will obviously
need to be based on mainline before it can be applied, I suppose that
means you are waiting for some series of his to be applied?

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-05 18:40               ` Julien Grall
@ 2014-05-06  8:58                 ` Ian Campbell
  2014-05-06  9:42                   ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-05-06  8:58 UTC (permalink / raw)
  To: Julien Grall
  Cc: Vijay Kilari, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Mon, 2014-05-05 at 19:40 +0100, Julien Grall wrote:

> As secure interrupt should not happen from the guest.

Surely it would be a silicon bug if it did, a secure interrupt should be
trapping to Secure EL3 not to NS EL2. What exactly are you asking Vijay
to handle here?

> You can check that 
> we correctly trap the access to thoses interrupts.

"trap access to interrupts" is meaningless AFAICT. Do you perhaps mean
"trap access to the XXX registers". For which XXX?

> >> The GICv3 spec requests to send a UNDEF exception if the register is not
> >> implemented.
> >>
> >> In general way, I think UNDEF is a best solution as some kernel such as
> >> Linux is able to recover from an undef on some specific access (it's
> >> actually the case for some debug registers on ARM32).
> >
> > In my understanding, calling inject_undef64_exception() will generate
> > UNDEF to guest.
> 
> Right. You have to call this function only if the domain is arm aarch64 
> guest.
> 
> AFAIU, it's possible to have GICv3 support when the guest is armv8 32 
> bit.

Is it? How do the system registers map onto the 32bit CP registers?

>  So you will have to call inject_undef32_exception for this case.

If it comes to this then please add inject_undef_exception which calls
the correct one for the guest type.

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-06  8:58                 ` Ian Campbell
@ 2014-05-06  9:42                   ` Julien Grall
  2014-05-06 10:10                     ` Ian Campbell
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-05-06  9:42 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Vijay Kilari, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 06/05/14 09:58, Ian Campbell wrote:
> On Mon, 2014-05-05 at 19:40 +0100, Julien Grall wrote:
>
>> As secure interrupt should not happen from the guest.
>
> Surely it would be a silicon bug if it did, a secure interrupt should be
> trapping to Secure EL3 not to NS EL2. What exactly are you asking Vijay
> to handle here?

With GICv3 it's possible to generate an SGI for another security state 
(see ICC_ASGI1R_EL1). We have to handle it like we do for smc call.

>
>> You can check that
>> we correctly trap the access to thoses interrupts.
>
> "trap access to interrupts" is meaningless AFAICT. Do you perhaps mean
> "trap access to the XXX registers". For which XXX?

Sorry, it's because theses registers is used to send an SGI. I think we 
have to trap ICC_ASGI1R_EL1, maybe ICC_SGI0R_EL1, just in case.

>>>> The GICv3 spec requests to send a UNDEF exception if the register is not
>>>> implemented.
>>>>
>>>> In general way, I think UNDEF is a best solution as some kernel such as
>>>> Linux is able to recover from an undef on some specific access (it's
>>>> actually the case for some debug registers on ARM32).
>>>
>>> In my understanding, calling inject_undef64_exception() will generate
>>> UNDEF to guest.
>>
>> Right. You have to call this function only if the domain is arm aarch64
>> guest.
>>
>> AFAIU, it's possible to have GICv3 support when the guest is armv8 32
>> bit.
>
> Is it? How do the system registers map onto the 32bit CP registers?

On aarch32, you can access to system registers via mrs/msr.

GICv3 is not mapped onto 32bit CP registers because there is a limited 
number of encodings available.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-06  9:42                   ` Julien Grall
@ 2014-05-06 10:10                     ` Ian Campbell
  2014-05-06 16:06                       ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Ian Campbell @ 2014-05-06 10:10 UTC (permalink / raw)
  To: Julien Grall
  Cc: Vijay Kilari, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On Tue, 2014-05-06 at 10:42 +0100, Julien Grall wrote:
> On 06/05/14 09:58, Ian Campbell wrote:
> > On Mon, 2014-05-05 at 19:40 +0100, Julien Grall wrote:
> >
> >> As secure interrupt should not happen from the guest.
> >
> > Surely it would be a silicon bug if it did, a secure interrupt should be
> > trapping to Secure EL3 not to NS EL2. What exactly are you asking Vijay
> > to handle here?
> 
> With GICv3 it's possible to generate an SGI for another security state 
> (see ICC_ASGI1R_EL1). We have to handle it like we do for smc call.

OK. Handling these like smc (i.e. undef and we'll deal with platform
specifics as they occur).

> 
> >
> >> You can check that
> >> we correctly trap the access to thoses interrupts.
> >
> > "trap access to interrupts" is meaningless AFAICT. Do you perhaps mean
> > "trap access to the XXX registers". For which XXX?
> 
> Sorry, it's because theses registers is used to send an SGI. I think we 
> have to trap ICC_ASGI1R_EL1, maybe ICC_SGI0R_EL1, just in case.

It looks like we will be trapping them, but you are right that we should
do something with them, #undef probably.

> 
> >>>> The GICv3 spec requests to send a UNDEF exception if the register is not
> >>>> implemented.
> >>>>
> >>>> In general way, I think UNDEF is a best solution as some kernel such as
> >>>> Linux is able to recover from an undef on some specific access (it's
> >>>> actually the case for some debug registers on ARM32).
> >>>
> >>> In my understanding, calling inject_undef64_exception() will generate
> >>> UNDEF to guest.
> >>
> >> Right. You have to call this function only if the domain is arm aarch64
> >> guest.
> >>
> >> AFAIU, it's possible to have GICv3 support when the guest is armv8 32
> >> bit.
> >
> > Is it? How do the system registers map onto the 32bit CP registers?
> 
> On aarch32, you can access to system registers via mrs/msr.

You meant mrc/mcr, but yes I see now.

> GICv3 is not mapped onto 32bit CP registers because there is a limited 
> number of encodings available.

Actually, since they use mrc/mcr they've effectively done just that
(whether or not they describe it that way).

Ian.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-06  8:55       ` Ian Campbell
@ 2014-05-06 14:11         ` Vijay Kilari
  2014-05-06 14:18           ` Julien Grall
  2014-05-07 16:30           ` Ian Campbell
  0 siblings, 2 replies; 107+ messages in thread
From: Vijay Kilari @ 2014-05-06 14:11 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Tue, May 6, 2014 at 2:25 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> On Mon, 2014-05-05 at 17:38 +0530, Vijay Kilari wrote:
>> > Shouldn't we panic here?
>> >
>> > And if we are going to panic, we might as well wait forever? (Perhaps
>> > with a warning after some number of iterations.
>> >
>>     Already after 1sec there is warning. I think warning is enough here
>> this is not such a critical scenario
>
> RWP timeout isn't critical? How does it get recovered?

   RWP is polled only to ensure that write effects are globally visibie.
   Spec does not define any recovery mechanism. In kernel driver
   this is prr_ratelimited.

   May be we can increase the timeout and panic.
>> >
>> > The dsb() macro needs a scope parameter for a while now. Which version
>> > of Xen is all this based on?
>>
>>   Based on Stefano's git where your scope parameter patch does not exist
>
> Stefano's git has dozens of branches in it. This series will obviously
> need to be based on mainline before it can be applied, I suppose that
> means you are waiting for some series of his to be applied?

   This patch set is based on no_maintenance_interrupts_v6 branch. I
would be glade
if you merge this series. Also Julien's patch set also impacts this series.
But for now I just rebasing only on Stefano's patch set

>
> Ian.
>

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-06 14:11         ` Vijay Kilari
@ 2014-05-06 14:18           ` Julien Grall
  2014-05-06 15:47             ` Julien Grall
  2014-05-07 16:30           ` Ian Campbell
  1 sibling, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-05-06 14:18 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 6 May 2014 15:11, Vijay Kilari <vijay.kilari@gmail.com> wrote:
>    This patch set is based on no_maintenance_interrupts_v6 branch. I
> would be glade
> if you merge this series. Also Julien's patch set also impacts this series.
> But for now I just rebasing only on Stefano's patch set

I will create a branch this afternoon with Stefano' s maintenance
interrupt v7 and my interrupt series.

I'll let you know when it' s done.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-06 14:18           ` Julien Grall
@ 2014-05-06 15:47             ` Julien Grall
  2014-05-22  5:58               ` Vijay Kilari
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-05-06 15:47 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 05/06/2014 03:18 PM, Julien Grall wrote:
> On 6 May 2014 15:11, Vijay Kilari <vijay.kilari@gmail.com> wrote:
>>    This patch set is based on no_maintenance_interrupts_v6 branch. I
>> would be glade
>> if you merge this series. Also Julien's patch set also impacts this series.
>> But for now I just rebasing only on Stefano's patch set
> 
> I will create a branch this afternoon with Stefano' s maintenance
> interrupt v7 and my interrupt series.

I've pushed a branch with both series:

git clone git://xenbits.xen.org/people/julieng/xen-unstable.git -b for-vijay


I'm able to boot dom0 with it (didn't try a guest).

FYI, Xen may get stuck on heavy load. Don't try to compile with -j4 on dom0 ;).
It's a known bug with those series.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 16/16] xen/arm: add SGI handling for GICv3
  2014-05-06 10:10                     ` Ian Campbell
@ 2014-05-06 16:06                       ` Julien Grall
  0 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-05-06 16:06 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Vijay Kilari, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

On 05/06/2014 11:10 AM, Ian Campbell wrote:
> You meant mrc/mcr, but yes I see now.

[..]

> Actually, since they use mrc/mcr they've effectively done just that
> (whether or not they describe it that way).

Oh right, for unknown reason I skipped important words in the sentence.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file
  2014-04-15 11:17 ` [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file vijay.kilari
  2014-04-15 19:10   ` Julien Grall
@ 2014-05-07 15:03   ` Julien Grall
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-05-07 15:03 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar

Hi Vijay,

On 15/04/14 12:17, vijay.kilari@gmail.com wrote:
> @@ -117,9 +118,14 @@ void domain_vgic_free(struct domain *d)
>   int vcpu_vgic_init(struct vcpu *v)
>   {
>       int i;
> -    memset(&v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
>
> -    spin_lock_init(&v->arch.vgic.private_irqs.lock);
> +    v->arch.vgic.private_irqs = xzalloc(struct vgic_irq_rank);
> +    if ( v->arch.vgic.private_irqs == NULL )
> +      return -ENOMEM;
> +
> +    memset(v->arch.vgic.private_irqs, 0, sizeof(v->arch.vgic.private_irqs));
> +

It's pointless to zeroed the memory here. xzalloc already did the job 
for you.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-06 14:11         ` Vijay Kilari
  2014-05-06 14:18           ` Julien Grall
@ 2014-05-07 16:30           ` Ian Campbell
  1 sibling, 0 replies; 107+ messages in thread
From: Ian Campbell @ 2014-05-07 16:30 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	xen-devel, Stefano Stabellini

On Tue, 2014-05-06 at 19:41 +0530, Vijay Kilari wrote:
> On Tue, May 6, 2014 at 2:25 PM, Ian Campbell <Ian.Campbell@citrix.com> wrote:
> > On Mon, 2014-05-05 at 17:38 +0530, Vijay Kilari wrote:
> >> > Shouldn't we panic here?
> >> >
> >> > And if we are going to panic, we might as well wait forever? (Perhaps
> >> > with a warning after some number of iterations.
> >> >
> >>     Already after 1sec there is warning. I think warning is enough here
> >> this is not such a critical scenario
> >
> > RWP timeout isn't critical? How does it get recovered?
> 
>    RWP is polled only to ensure that write effects are globally visibie.
>    Spec does not define any recovery mechanism. In kernel driver
>    this is prr_ratelimited.

My point was that the global visibility seems pretty important,
especially given the lack of a recovery mechanism.

>    May be we can increase the timeout and panic.

How about we print/warn after some timeout bit then continue to wait, on
the off chance that things recover?

I suppose panicing would cause a reboot which would be nice in so far as
it night unwedge things.

> >> >
> >> > The dsb() macro needs a scope parameter for a while now. Which version
> >> > of Xen is all this based on?
> >>
> >>   Based on Stefano's git where your scope parameter patch does not exist
> >
> > Stefano's git has dozens of branches in it. This series will obviously
> > need to be based on mainline before it can be applied, I suppose that
> > means you are waiting for some series of his to be applied?
> 
>    This patch set is based on no_maintenance_interrupts_v6 branch. I
> would be glade
> if you merge this series. Also Julien's patch set also impacts this series.
> But for now I just rebasing only on Stefano's patch set
> 
> >
> > Ian.
> >

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure
  2014-04-15 11:17 ` [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure vijay.kilari
  2014-04-23 14:35   ` Ian Campbell
@ 2014-05-12 13:49   ` Julien Grall
  1 sibling, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-05-12 13:49 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar

Hi Vijay,

On 04/15/2014 12:17 PM, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> spinlock is used across generic and GIC low level
> functions. Move this lock out of gic data.
> This helps to separate generic and low level functions
> later.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/gic.c |   35 ++++++++++++++++++-----------------
>  1 file changed, 18 insertions(+), 17 deletions(-)
> 
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 05f2240..7c9a408 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -35,6 +35,8 @@
>  #include <asm/gic_v2_defs.h>
>  #include <asm/gic.h>
>  
> +static spinlock_t gic_lock;
> +

You can directly use DEFINE_SPINCLOCK(gic_lock). This will avoid the
spin_lock_init in gic_init.

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-06 15:47             ` Julien Grall
@ 2014-05-22  5:58               ` Vijay Kilari
  2014-05-22  9:26                 ` Julien Grall
  0 siblings, 1 reply; 107+ messages in thread
From: Vijay Kilari @ 2014-05-22  5:58 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini

Hi Julien,

On Tue, May 6, 2014 at 9:17 PM, Julien Grall <julien.grall@linaro.org> wrote:
> On 05/06/2014 03:18 PM, Julien Grall wrote:
>> On 6 May 2014 15:11, Vijay Kilari <vijay.kilari@gmail.com> wrote:
>>>    This patch set is based on no_maintenance_interrupts_v6 branch. I
>>> would be glade
>>> if you merge this series. Also Julien's patch set also impacts this series.
>>> But for now I just rebasing only on Stefano's patch set
>>
>> I will create a branch this afternoon with Stefano' s maintenance
>> interrupt v7 and my interrupt series.
>
> I've pushed a branch with both series:
>
> git clone git://xenbits.xen.org/people/julieng/xen-unstable.git -b for-vijay

   Thanks for this branch. I have observed locking issues with
multicore (>2 cpus).
Dom0 boot freezes randomly. Have u tested with >2 cpu's?.
I could not test your patches alone. Can you please confirm that this branch
is stable with multicore with GICv2?

>
>
> I'm able to boot dom0 with it (didn't try a guest).
>
> FYI, Xen may get stuck on heavy load. Don't try to compile with -j4 on dom0 ;).
> It's a known bug with those series.
>
> Regards,
>
> --
> Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-22  5:58               ` Vijay Kilari
@ 2014-05-22  9:26                 ` Julien Grall
  2014-05-22 12:36                   ` Stefano Stabellini
  0 siblings, 1 reply; 107+ messages in thread
From: Julien Grall @ 2014-05-22  9:26 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	xen-devel, Stefano Stabellini



On 22/05/14 06:58, Vijay Kilari wrote:
> Hi Julien,

Hi Vijay,

> On Tue, May 6, 2014 at 9:17 PM, Julien Grall <julien.grall@linaro.org> wrote:
>> On 05/06/2014 03:18 PM, Julien Grall wrote:
>>> On 6 May 2014 15:11, Vijay Kilari <vijay.kilari@gmail.com> wrote:
>>>>     This patch set is based on no_maintenance_interrupts_v6 branch. I
>>>> would be glade
>>>> if you merge this series. Also Julien's patch set also impacts this series.
>>>> But for now I just rebasing only on Stefano's patch set
>>>
>>> I will create a branch this afternoon with Stefano' s maintenance
>>> interrupt v7 and my interrupt series.
>>
>> I've pushed a branch with both series:
>>
>> git clone git://xenbits.xen.org/people/julieng/xen-unstable.git -b for-vijay
>
>     Thanks for this branch. I have observed locking issues with
> multicore (>2 cpus).
> Dom0 boot freezes randomly. Have u tested with >2 cpu's?.
> I could not test your patches alone. Can you please confirm that this branch
> is stable with multicore with GICv2?

It might be related to the hang the we see on Stefano's maintenance 
interrupts series. I think he has fixed it in his development branch.

Stefano, can you confirm it?

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-05-22  9:26                 ` Julien Grall
@ 2014-05-22 12:36                   ` Stefano Stabellini
  0 siblings, 0 replies; 107+ messages in thread
From: Stefano Stabellini @ 2014-05-22 12:36 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Vijay Kilari, Stefano Stabellini, Prasun Kapoor,
	Vijaya Kumar K, xen-devel, Stefano Stabellini

On Thu, 22 May 2014, Julien Grall wrote:
> On 22/05/14 06:58, Vijay Kilari wrote:
> > Hi Julien,
> 
> Hi Vijay,
> 
> > On Tue, May 6, 2014 at 9:17 PM, Julien Grall <julien.grall@linaro.org>
> > wrote:
> > > On 05/06/2014 03:18 PM, Julien Grall wrote:
> > > > On 6 May 2014 15:11, Vijay Kilari <vijay.kilari@gmail.com> wrote:
> > > > >     This patch set is based on no_maintenance_interrupts_v6 branch. I
> > > > > would be glade
> > > > > if you merge this series. Also Julien's patch set also impacts this
> > > > > series.
> > > > > But for now I just rebasing only on Stefano's patch set
> > > > 
> > > > I will create a branch this afternoon with Stefano' s maintenance
> > > > interrupt v7 and my interrupt series.
> > > 
> > > I've pushed a branch with both series:
> > > 
> > > git clone git://xenbits.xen.org/people/julieng/xen-unstable.git -b
> > > for-vijay
> > 
> >     Thanks for this branch. I have observed locking issues with
> > multicore (>2 cpus).
> > Dom0 boot freezes randomly. Have u tested with >2 cpu's?.
> > I could not test your patches alone. Can you please confirm that this branch
> > is stable with multicore with GICv2?
> 
> It might be related to the hang the we see on Stefano's maintenance interrupts
> series. I think he has fixed it in his development branch.
> 
> Stefano, can you confirm it?

Yes, I found a few bugs in the series that can cause a full hypervisor
locking.
Please checkout the latest version:

http://marc.info/?l=xen-devel&m=140076202414100

I have tested it for a few consecutive days and I haven't found any
more issues. I am very sorry if it caused you any troubles.

You should also know that on another ARMv8 board the series doesn't work
correctly, because the hardware implementation of GICH_LR_HW seems to be
defective. It works fine on a Cortex A15 though.

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v3 13/16] xen/arm: Add support for GIC v3
  2014-04-23 17:01   ` Ian Campbell
  2014-04-23 17:24     ` Julien Grall
  2014-05-05 12:08     ` Vijay Kilari
@ 2014-05-27 18:17     ` Julien Grall
  2 siblings, 0 replies; 107+ messages in thread
From: Julien Grall @ 2014-05-27 18:17 UTC (permalink / raw)
  To: Ian Campbell, vijay.kilari
  Cc: Prasun.Kapoor, vijaya.kumar, xen-devel, stefano.stabellini,
	stefano.stabellini

On 04/23/2014 06:01 PM, Ian Campbell wrote:
> On Tue, 2014-04-15 at 16:47 +0530, vijay.kilari@gmail.com wrote:
> 
>> +#include <xen/config.h>
>> +#include <xen/lib.h>
>> +#include <xen/init.h>
>> +#include <xen/cpu.h>
>> +#include <xen/mm.h>
>> +#include <xen/irq.h>
>> +#include <xen/sched.h>
>> +#include <xen/errno.h>
>> +#include <xen/serial.h>
>> +#include <xen/softirq.h>
>> +#include <xen/list.h>
>> +#include <xen/device_tree.h>
>> +#include <xen/delay.h>
>> +#include <asm/p2m.h>
>> +#include <asm/domain.h>
>> +#include <asm/platform.h>
> 
> Do you really need all of these? serial.h for example?
> 
>> +
>> +#include <asm/gic_v3_defs.h>
>> +#include <asm/gic.h>
>> +#include <asm/io.h>
>> +#include <asm/device.h>
>> +
>> +static struct gic_hw_operations gic_ops;
>> +
>> +struct rdist_region {
>> +    paddr_t rdist_base;
>> +    paddr_t rdist_base_size;
>> +    void __iomem *map_rdist_base;
> 
> "base", "size" and "map" would be adequate field names I think.
> 
>> +};
>> +
>> +/* Global state */
>> +static struct {
>> +    paddr_t dbase;            /* Address of distributor registers */
>> +    paddr_t dbase_size;
>> +    void __iomem *map_dbase;  /* Mapped address of distributor registers */
>> +    struct rdist_region *rdist_regions;
>> +    u32  rdist_stride;
>> +    unsigned int rdist_count; /* Number of rdist regions count */
>> +    unsigned int lines;       /* Number of interrupts (SPIs + PPIs + SGIs) */
>> +    struct dt_irq maintenance;
>> +}gic;
>> +
>> +/* per-cpu re-distributor base */
>> +static DEFINE_PER_CPU(void __iomem*, rbase);
> 
> Does this end up containing one of the gic.rdist_regions[i].map entries?
> Any reason to duplicate this in that map field as well? Can't each
> processor map it as it is initialised and store it here directly?
> 
> I suppose we have plenty of ioremap space on v8, so nr_cpus*2*64k isn't
> too bad and there's no need to go for per-pcpu pagetables with a
> dedicated virtual address region for the redistributors.
> 
>> +static u64 gich_read_lr(int lr)
>> +{
>> +    switch ( lr )
>> +    {
>> +    case 0: /* ICH_LRn is 64 bit */
>> +        return READ_SYSREG(ICH_LR0_EL2);
>> +        break;
> 
> All of these breaks are redundant. I think you could get away with
> 	case N: return READ_(..._LRn_EL2);
> for brevity even.
>> +
>> +/* Wait for completion of a distributor change */
>> +static void gicv3_do_wait_for_rwp(void __iomem *base)
>> +{
>> +    u32 val;
>> +    u32 count = 1000000;
>> +
>> +    do {
>> +        val = readl_relaxed(base + GICD_CTLR);
>> +        if ( !(val & GICD_CTLR_RWP) )
>> +           break;
>> +        cpu_relax();
>> +        udelay(1);
> 
> Ick. Is there no event when rwp changes, so we could do wfe here?
> 
> Could we at least use NOW() and MILLISECS() to construct a delay of a
> known length?
> 
>> +    } while ( count-- );
>> +
>> +    if ( !count )
>> +        dprintk(XENLOG_WARNING, "RWP timeout\n");
> 
> Shouldn't we panic here?
> 
> And if we are going to panic, we might as well wait forever? (Perhaps
> with a warning after some number of iterations.
> 
>> +static unsigned int gicv3_mask_cpu(const cpumask_t *cpumask)
> 
> this returns an arbitrary cpu from cpumask? Can we name it as such
> please.
> 
> The v2 equivalent returns a value suitable for GICD_ITARGETSR, which
> might contain multiple valid target CPUs. Does GICD_IROUTER not have the
> same property?
> 
>> +{
>> +    unsigned int cpu;
>> +    cpumask_t possible_mask;
>> +
>> +    cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
>> +    cpu = cpumask_any(&possible_mask);
>> +    return cpu;
>> +}
>> +
>> +static void write_aprn_regs(union gic_state_data *d)
> 
> Given the usage I think this should be restore_aprn_regs.
> 
>> +{
>> +    ASSERT((nr_priorities > 4 && nr_priorities < 8));
>> +    /* Write APRn register based on number of priorities
>> +       plaform has implemented */
> 
> "platform"
> 
>> +    switch ( nr_priorities )
>> +    {
>> +    case 7:
>> +        WRITE_SYSREG32(d->v3.apr0[2], ICH_AP0R2_EL2);
>> +        WRITE_SYSREG32(d->v3.apr1[2], ICH_AP1R2_EL2);
>> +        /* Fall through */
>> +    case 6:
>> +        WRITE_SYSREG32(d->v3.apr0[1], ICH_AP0R1_EL2);
>> +        WRITE_SYSREG32(d->v3.apr1[1], ICH_AP1R1_EL2);
>> +        /* Fall through */
>> +    case 5:
>> +        WRITE_SYSREG32(d->v3.apr0[0], ICH_AP0R0_EL2);
>> +        WRITE_SYSREG32(d->v3.apr1[0], ICH_AP1R0_EL2);
>> +        break;
>> +    default:
> 
> BUG_ON?
> 
>> +        break;
>> +    }
>> +}
>> +
>> +static void read_aprn_regs(union gic_state_data *d)
> 
> The same three comments as write_* apply here too.
> 
>> +static void gicv3_save_state(struct vcpu *v)
>> +{
>> +    int i;
>> +
>> +    /* No need for spinlocks here because interrupts are disabled around
>> +     * this call and it only accesses struct vcpu fields that cannot be
>> +     * accessed simultaneously by another pCPU.
>> +     */
>> +    for ( i = 0; i < nr_lrs; i++)
>> +        v->arch.gic.v3.lr[i] = gich_read_lr(i);
>> +
>> +    read_aprn_regs(&v->arch.gic); 
>> +    v->arch.gic.v3.vmcr = READ_SYSREG32(ICH_VMCR_EL2);
>> +}
>> +
>> +static void gicv3_restore_state(struct vcpu *v)
>> +{
>> +    int i;
>> +
>> +    for ( i = 0; i < nr_lrs; i++)
>> +        gich_write_lr(i, v->arch.gic.v3.lr[i]);
> 
> I wonder if the compiler could do a better job of this using the same
> switch and fallthrough method you used for aprn regs?
> 
>> +
>> +    write_aprn_regs(&v->arch.gic);
>> +
>> +    WRITE_SYSREG32(v->arch.gic.v3.vmcr, ICH_VMCR_EL2);
>> +}
> 
>> +static void gicv3_enable_irq(struct irq_desc *irqd)
>> +{
>> +    int irq = irqd->irq;
>> +    uint32_t enabler;
>> +
>> +    /* Enable routing */
>> +    if ( irq < NR_GIC_LOCAL_IRQS )
>> +    {
>> +        enabler = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
>> +        enabler |= (1u << irq);
>> +        writel_relaxed(enabler, GICD_RDIST_SGI_BASE + GICR_ISENABLER0);
> 
> I don't think the enable registers need read-modufy-wirte, do they? You
> just write the bit you want to enable, like you do with the clear
> ICENABLER registers.
> 
>> +static u64 gic_mpidr_to_affinity(u64 mpidr)
>> +{
>> +    u64 aff;
>> +    /* Make sure we don't broadcast the interrupt */
>> +     aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
> 
> Indentation here is squiffy.
> 
>> +            MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
>> +            MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
>> +            MPIDR_AFFINITY_LEVEL(mpidr, 0)) & ~GICD_IROUTER_SPI_MODE_ANY;
>> +    return aff;
>> +}
>> +
>> +/*
>> + * - needs to be called with gic.lock held
>> + * - needs to be called with a valid cpu_mask, ie each cpu in the mask has
>> + * already called gic_cpu_init
>> + */
>> +static void gicv3_set_irq_property(unsigned int irq, bool_t level,
>> +                                   const cpumask_t *cpu_mask,
>> +                                   unsigned int priority)
>> +{
>> +    uint32_t cfg, edgebit;
>> +    u64 affinity;
>> +    unsigned int cpu = gicv3_mask_cpu(cpu_mask);
>> +
>> +
>> +    /* Set edge / level */
>> +    if ( irq < NR_GIC_SGI )
>> +        /* SGI's are always edge-triggered not need to call GICD_ICFGR0 */
> 
> s/not/no/ I think.
> 
> But then given the comment you do anyway?
> 
>> +        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR0);
>> +    else if ( irq < NR_GIC_LOCAL_IRQS )
>> +        cfg = readl_relaxed(GICD_RDIST_SGI_BASE + GICR_ICFGR1);
>> +    else
>> +        cfg = readl_relaxed(GICD + GICD_ICFGR + (irq / 16) * 4);
>> +
>> +    edgebit = 2u << (2 * (irq % 16));
>> +    if ( level )
>> +        cfg &= ~edgebit;
>> +    else
>> +        cfg |= edgebit;
>> +
>> +    if ( irq < NR_GIC_SGI )
>> +       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR0);
>> +    else if ( irq < NR_GIC_LOCAL_IRQS )
>> +       writel_relaxed(cfg, GICD_RDIST_SGI_BASE + GICR_ICFGR1);
>> +    else
>> +       writel_relaxed(cfg, GICD + GICD_ICFGR + (irq / 16) * 4);
>> +
>> +    affinity = gic_mpidr_to_affinity(cpu_logical_map(cpu));
>> +    if ( irq >= NR_GIC_LOCAL_IRQS )
>> +        writeq_relaxed(affinity, (GICD + GICD_IROUTER + irq * 8));
>> +
>> +    /* Set priority */
>> +    if ( irq < NR_GIC_LOCAL_IRQS )
>> +    {
> 
> The {}s here aren't needed.
> 
>> +        writeb_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + irq);
>> +    }
>> +    else 
>> +    {
>> +        writeb_relaxed(priority, GICD + GICD_IPRIORITYR + irq);
>> +    }
>> +}
>> +
>> +static void gicv3_enable_redist(void)
>> +{
>> +    u32 val;
>> +    /* Wait for 1s */
>> +    u32 count = 1000000;
> 
> NOW() + MILLISECS(...) based again?
> 
>> +
>> +    /* Wake up this CPU redistributor */
>> +    val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
>> +    val &= ~GICR_WAKER_ProcessorSleep;
>> +    writel_relaxed(val, GICD_RDIST_BASE + GICR_WAKER);
>> +
>> +    do {
>> +         val = readl_relaxed(GICD_RDIST_BASE + GICR_WAKER);
>> +         if ( !(val & GICR_WAKER_ChildrenAsleep) )
>> +           break;
>> +         cpu_relax();
>> +         udelay(1);
>> +    } while ( count-- );
>> +
>> +    if ( !count )
>> +        gdprintk(XENLOG_WARNING, "Redist enable RWP timeout\n");
>> +}
>> +
>> +static int __init gicv3_populate_rdist(void)
>> +{
>> +    u64 mpidr = cpu_logical_map(smp_processor_id());
>> +    u64 typer;
>> +    uint32_t aff;
> 
> You have an interesting mix of u64 and uint32_t. Please stick to one or
> the other, preferable uintXX_t.
> 
>> +    int i;
>> +    uint32_t reg;
>> +
>> +    aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
>> +           MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
>> +           MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
>> +           MPIDR_AFFINITY_LEVEL(mpidr, 0));
> 
> Is this not gic_mpidr_to_affinity?

Actually it's not the same. The "level 3" is shift of 24 rather than 32.
This is to match TYPER register.

Linux code (where this function came from) has a comment above this
"Convert affinity to a 32bit value that can be matched to GICR_TYPER
bits [63:32]."

Regards,

-- 
Julien Grall

^ permalink raw reply	[flat|nested] 107+ messages in thread

end of thread, other threads:[~2014-05-27 18:17 UTC | newest]

Thread overview: 107+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-15 11:17 [PATCH v3 00/16] xen/arm: Add GICv3 support vijay.kilari
2014-04-15 11:17 ` [PATCH v3 01/16] xen/arm: move io.h as mmio.h to include folder vijay.kilari
2014-04-15 16:36   ` Julien Grall
2014-04-23 14:16   ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 02/16] xen/arm: make mmio handlers domain specific vijay.kilari
2014-04-15 17:07   ` Julien Grall
2014-04-23 14:27     ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 03/16] xen/arm: make sgi handling generic vijay.kilari
2014-04-15 17:51   ` Julien Grall
2014-04-15 17:57     ` Julien Grall
2014-04-23 14:31     ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 04/16] xen/arm: remove unused parameter in do_sgi call vijay.kilari
2014-04-15 17:52   ` Julien Grall
2014-04-23 14:32   ` Ian Campbell
2014-04-25  9:28     ` Vijay Kilari
2014-04-15 11:17 ` [PATCH v3 05/16] xen/arm: move gic definitions to seperate file vijay.kilari
2014-04-23 14:34   ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 06/16] xen/arm: move gic lock out of gic data structure vijay.kilari
2014-04-23 14:35   ` Ian Campbell
2014-05-12 13:49   ` Julien Grall
2014-04-15 11:17 ` [PATCH v3 07/16] xen/arm: segregate and split GIC low level functionality vijay.kilari
2014-04-15 18:35   ` Julien Grall
2014-04-23 14:55     ` Ian Campbell
2014-04-23 15:01       ` Julien Grall
2014-04-23 16:47         ` Julien Grall
2014-04-23 17:03           ` Ian Campbell
2014-04-23 17:09             ` Julien Grall
2014-04-24  8:58               ` Ian Campbell
2014-04-24  8:19           ` Ian Campbell
2014-04-28 11:48     ` Vijay Kilari
2014-04-28 12:06       ` Julien Grall
2014-04-28 13:10         ` Vijay Kilari
2014-04-28 13:12           ` Julien Grall
2014-04-15 21:00   ` Julien Grall
2014-04-23 14:52   ` Ian Campbell
2014-04-28 14:41     ` Vijay Kilari
2014-04-28 14:58       ` Ian Campbell
2014-04-28 15:10       ` Julien Grall
2014-04-15 11:17 ` [PATCH v3 08/16] arm/xen: move GIC context data structure to gic driver vijay.kilari
2014-04-15 18:41   ` Julien Grall
2014-04-23 14:57     ` Ian Campbell
2014-04-23 14:58   ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 09/16] xen/arm: use device api to detect GIC version vijay.kilari
2014-04-15 18:49   ` Julien Grall
2014-04-23 15:01   ` Ian Campbell
2014-04-29  7:07     ` Vijay Kilari
2014-04-29  8:55       ` Ian Campbell
2014-04-29 10:13         ` Julien Grall
2014-04-15 11:17 ` [PATCH v3 10/16] xen/arm: move vgic rank data to gic header file vijay.kilari
2014-04-15 19:10   ` Julien Grall
2014-04-17  6:48     ` Vijay Kilari
2014-05-07 15:03   ` Julien Grall
2014-04-15 11:17 ` [PATCH v3 11/16] xen/arm: move vgic defines to vgic " vijay.kilari
2014-04-16 17:01   ` Julien Grall
2014-04-23 15:07     ` Ian Campbell
2014-04-23 15:11       ` Julien Grall
2014-04-23 15:15         ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 12/16] xen/arm: split vgic driver into generic and vgic-v2 driver vijay.kilari
2014-04-15 20:05   ` Julien Grall
2014-04-23 15:12   ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 13/16] xen/arm: Add support for GIC v3 vijay.kilari
2014-04-15 20:43   ` Julien Grall
2014-04-17  7:09     ` Vijay Kilari
2014-04-17  8:58       ` Ian Campbell
2014-04-17  9:02       ` Julien Grall
2014-04-17  9:57   ` Julien Grall
2014-04-17 11:00     ` Vijay Kilari
2014-04-17 11:17       ` Julien Grall
2014-04-17 14:54         ` Vijay Kilari
2014-04-17 15:12           ` Julien Grall
2014-04-23 17:01   ` Ian Campbell
2014-04-23 17:24     ` Julien Grall
2014-04-29 12:35       ` Vijay Kilari
2014-05-05 12:08     ` Vijay Kilari
2014-05-06  8:55       ` Ian Campbell
2014-05-06 14:11         ` Vijay Kilari
2014-05-06 14:18           ` Julien Grall
2014-05-06 15:47             ` Julien Grall
2014-05-22  5:58               ` Vijay Kilari
2014-05-22  9:26                 ` Julien Grall
2014-05-22 12:36                   ` Stefano Stabellini
2014-05-07 16:30           ` Ian Campbell
2014-05-27 18:17     ` Julien Grall
2014-04-15 11:17 ` [PATCH v3 14/16] xen/arm: Add virtual GICv3 support vijay.kilari
2014-04-17  9:27   ` Julien Grall
2014-04-24 10:37     ` Ian Campbell
2014-04-24 11:39       ` Julien Grall
2014-04-24 10:30   ` Ian Campbell
2014-05-02  9:43     ` Vijay Kilari
2014-05-02  9:56       ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 15/16] xen/arm: Update Dom0 GIC dt node with GICv3 information vijay.kilari
2014-04-18 19:57   ` Julien Grall
2014-04-24 10:46   ` Ian Campbell
2014-04-15 11:17 ` [PATCH v3 16/16] xen/arm: add SGI handling for GICv3 vijay.kilari
2014-04-18 20:20   ` Julien Grall
2014-05-02 12:57     ` Vijay Kilari
2014-05-02 14:26       ` Julien Grall
2014-05-02 15:18         ` Ian Campbell
2014-05-02 15:24           ` Julien Grall
2014-05-05  6:53             ` Vijay Kilari
2014-05-05 18:40               ` Julien Grall
2014-05-06  8:58                 ` Ian Campbell
2014-05-06  9:42                   ` Julien Grall
2014-05-06 10:10                     ` Ian Campbell
2014-05-06 16:06                       ` Julien Grall
2014-04-24 10:57   ` Ian Campbell
2014-04-24 11:43     ` Julien Grall

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.