All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/19] xen/arm: Add ITS support
@ 2015-03-02 12:30 vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 01/19] xen/arm: add linked list apis vijay.kilari
                   ` (20 more replies)
  0 siblings, 21 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Add ITS support for arm. Following major features
are supported
 - GICv3 ITS support for arm64 platform
 - Supports only single ITS node
 - LPI descriptors are allocated on-demand
 - Only ITS Dom0 is supported

Vijaya Kumar K (19):
  xen/arm: add linked list apis
  xen/arm: its: Import GICv3 ITS driver from linux
  xen/arm: its: Port ITS driver to xen
  xen/arm: its: Move ITS command encode helper functions
  xen/arm: its: Remove unused code in ITS driver
  xen/arm: its: Add helper functions to decode ITS Command
  xen/arm: vits: Move LPI handling to basic virtual its driver
  xen/arm: Add helper function to get domain page
  xen/arm: Update irq descriptor for LPIs support
  xen/arm: its: Add virtual ITS command support
  xen/arm: its: Add emulation of ITS control registers
  xen/arm: its: Add support to emulate GICR register for LPIs
  xen/arm: its: implement hw_irq_controller for LPIs
  xen/arm: vits: Map ITS translation space
  xen/arm: gicv3: Refactor redistributor information
  xen/arm: its: Dynamic allocation of LPI descriptors
  xen/arm: its: Support ITS interrupt handling
  xen/arm: its: Generate ITS node for Dom0
  xen/arm: its: Initialize virtual and physical ITS driver

 xen/arch/arm/Makefile             |    2 +
 xen/arch/arm/domain_build.c       |   59 +-
 xen/arch/arm/gic-v3-its.c         | 1074 +++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c             |   45 +-
 xen/arch/arm/gic.c                |   59 +-
 xen/arch/arm/irq.c                |  211 ++++-
 xen/arch/arm/p2m.c                |   24 +
 xen/arch/arm/setup.c              |    1 +
 xen/arch/arm/vgic-v3-its.c        | 1580 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic-v3.c            |   65 +-
 xen/arch/arm/vgic.c               |   34 +-
 xen/common/device_tree.c          |    2 +
 xen/include/asm-arm/domain.h      |    7 +
 xen/include/asm-arm/gic-its.h     |  256 ++++++
 xen/include/asm-arm/gic.h         |   26 +-
 xen/include/asm-arm/gic_v3_defs.h |  130 +++
 xen/include/asm-arm/irq.h         |   14 +-
 xen/include/asm-arm/p2m.h         |    3 +
 xen/include/asm-arm/vgic.h        |    1 +
 xen/include/xen/device_tree.h     |    1 +
 xen/include/xen/irq.h             |    2 +
 xen/include/xen/list.h            |   33 +
 22 files changed, 3593 insertions(+), 36 deletions(-)
 create mode 100644 xen/arch/arm/gic-v3-its.c
 create mode 100644 xen/arch/arm/vgic-v3-its.c
 create mode 100644 xen/include/asm-arm/gic-its.h

-- 
1.7.9.5

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

* [RFC PATCH 01/19] xen/arm: add linked list apis
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 13:21   ` Jan Beulich
  2015-03-02 12:30 ` [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux vijay.kilari
                   ` (19 subsequent siblings)
  20 siblings, 1 reply; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, Jan Beulich, manish.jaggi, vijay.kilari

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

Add missing linked list apis from kernel

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
CC: Jan Beulich <JBeulich@suse.com>
---
 xen/include/xen/list.h |   33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/xen/include/xen/list.h b/xen/include/xen/list.h
index 59cf571..0e1c6b4 100644
--- a/xen/include/xen/list.h
+++ b/xen/include/xen/list.h
@@ -385,6 +385,39 @@ static inline void list_splice_init(struct list_head *list,
     container_of(ptr, type, member)
 
 /**
+ * list_first_entry - get the first element from a list
+ * @ptr:        the list head to take the element from.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+        list_entry((ptr)->next, type, member)
+
+/**
+ * list_last_entry - get the last element from a list
+ * @ptr:        the list head to take the element from.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_last_entry(ptr, type, member) \
+        list_entry((ptr)->prev, type, member)
+
+/**
+ * list_first_entry_or_null - get the first element from a list
+ * @ptr:        the list head to take the element from.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Note that if the list is empty, it returns NULL.
+ */
+#define list_first_entry_or_null(ptr, type, member) \
+        (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+/**
  * list_for_each    -    iterate over a list
  * @pos:    the &struct list_head to use as a loop cursor.
  * @head:    the head for your list.
-- 
1.7.9.5

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

* [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 01/19] xen/arm: add linked list apis vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-13 10:24   ` Julien Grall
  2015-03-02 12:30 ` [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen vijay.kilari
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

This is actual GICv3 ITS driver from linux.
No xen related changes are made and is not compiled.

This helps to import any issues found in linux

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

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
new file mode 100644
index 0000000..28b72e4
--- /dev/null
+++ b/xen/arch/arm/gic-v3-its.c
@@ -0,0 +1,1348 @@
+/*
+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/log2.h>
+#include <linux/mm.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
+
+#include <linux/irqchip/arm-gic-v3.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING        (1 << 0)
+
+#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
+
+/*
+ * Collection structure - just an ID, and a redistributor address to
+ * ping. We use one per CPU as a bag of interrupts assigned to this
+ * CPU.
+ */
+struct its_collection {
+    u64 target_address;
+    u16 col_id;
+};
+
+/*
+ * The ITS structure - contains most of the infrastructure, with the
+ * msi_chip, the command queue, the collections, and the list of
+ * devices writing to it.
+ */
+struct its_node {
+    raw_spinlock_t        lock;
+    struct                list_head entry;
+    struct msi_chip       msi_chip;
+    void __iomem          *base;
+    unsigned long         phys_base;
+    struct its_cmd_block  *cmd_base;
+    struct its_cmd_block  *cmd_write;
+    void                  *tables[GITS_BASER_NR_REGS];
+    struct its_collection *collections;
+    struct list_head      its_device_list;
+    u64                   flags;
+    u32                   ite_size;
+};
+
+#define ITS_ITT_ALIGN        SZ_256
+
+/*
+ * The ITS view of a device - belongs to an ITS, a collection, owns an
+ * interrupt translation table, and a list of interrupts.
+ */
+struct its_device {
+    struct list_head       entry;
+    struct its_node        *its;
+    struct its_collection  *collection;
+    void                   *itt;
+    unsigned long          *lpi_map;
+    int                    lpi_base;
+    int                    nr_lpis;
+    u32                    nr_ites;
+    u32                    device_id;
+};
+
+static LIST_HEAD(its_nodes);
+static DEFINE_SPINLOCK(its_lock);
+static struct irq_domain  *lpi_domain;
+static struct device_node *gic_root_node;
+static struct rdists      *gic_rdists;
+
+#define gic_data_rdist()        (raw_cpu_ptr(gic_rdists->rdist))
+#define gic_data_rdist_rd_base()    (gic_data_rdist()->rd_base)
+
+/*
+ * ITS command descriptors - parameters to be encoded in a command
+ * block.
+ */
+struct its_cmd_desc {
+    union {
+        struct {
+            struct its_device *dev;
+            u32 event_id;
+        } its_inv_cmd;
+
+        struct {
+            struct its_device *dev;
+            u32 event_id;
+        } its_int_cmd;
+
+        struct {
+            struct its_device *dev;
+            int valid;
+        } its_mapd_cmd;
+
+        struct {
+            struct its_collection *col;
+            int valid;
+        } its_mapc_cmd;
+
+        struct {
+            struct its_device *dev;
+            u32 phys_id;
+            u32 event_id;
+        } its_mapvi_cmd;
+
+        struct {
+            struct its_device *dev;
+            struct its_collection *col;
+            u32 id;
+        } its_movi_cmd;
+
+        struct {
+            struct its_device *dev;
+            u32 event_id;
+        } its_discard_cmd;
+
+        struct {
+            struct its_collection *col;
+        } its_invall_cmd;
+    };
+};
+
+/*
+ * The ITS command block, which is what the ITS actually parses.
+ */
+struct its_cmd_block {
+    u64 raw_cmd[4];
+};
+
+#define ITS_CMD_QUEUE_SZ            SZ_64K
+#define ITS_CMD_QUEUE_NR_ENTRIES    (ITS_CMD_QUEUE_SZ / sizeof(struct its_cmd_block))
+
+typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
+                                struct its_cmd_desc *);
+
+static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
+{
+    cmd->raw_cmd[0] &= ~0xffULL;
+    cmd->raw_cmd[0] |= cmd_nr;
+}
+
+static void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
+{
+    cmd->raw_cmd[0] &= 0xffffffffULL;
+    cmd->raw_cmd[0] |= ((u64)devid) << 32;
+}
+
+static void its_encode_event_id(struct its_cmd_block *cmd, u32 id)
+{
+    cmd->raw_cmd[1] &= ~0xffffffffULL;
+    cmd->raw_cmd[1] |= id;
+}
+
+static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id)
+{
+    cmd->raw_cmd[1] &= 0xffffffffULL;
+    cmd->raw_cmd[1] |= ((u64)phys_id) << 32;
+}
+
+static void its_encode_size(struct its_cmd_block *cmd, u8 size)
+{
+    cmd->raw_cmd[1] &= ~0xffULL;
+    cmd->raw_cmd[1] |= size;
+}
+
+static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr)
+{
+    cmd->raw_cmd[2] &= ~0xffffffffffffULL;
+    cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00ULL;
+}
+
+static void its_encode_valid(struct its_cmd_block *cmd, int valid)
+{
+    cmd->raw_cmd[2] &= ~(1ULL << 63);
+    cmd->raw_cmd[2] |= ((u64)!!valid) << 63;
+}
+
+static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr)
+{
+    cmd->raw_cmd[2] &= ~(0xffffffffULL << 16);
+    cmd->raw_cmd[2] |= (target_addr & (0xffffffffULL << 16));
+}
+
+static void its_encode_collection(struct its_cmd_block *cmd, u16 col)
+{
+    cmd->raw_cmd[2] &= ~0xffffULL;
+    cmd->raw_cmd[2] |= col;
+}
+
+static inline void its_fixup_cmd(struct its_cmd_block *cmd)
+{
+    /* Let's fixup BE commands */
+    cmd->raw_cmd[0] = cpu_to_le64(cmd->raw_cmd[0]);
+    cmd->raw_cmd[1] = cpu_to_le64(cmd->raw_cmd[1]);
+    cmd->raw_cmd[2] = cpu_to_le64(cmd->raw_cmd[2]);
+    cmd->raw_cmd[3] = cpu_to_le64(cmd->raw_cmd[3]);
+}
+
+static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
+                                                 struct its_cmd_desc *desc)
+{
+    unsigned long itt_addr;
+    u8 size = max(order_base_2(desc->its_mapd_cmd.dev->nr_ites), 1);
+
+    itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
+    itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
+
+    its_encode_cmd(cmd, GITS_CMD_MAPD);
+    its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id);
+    its_encode_size(cmd, size - 1);
+    its_encode_itt(cmd, itt_addr);
+    its_encode_valid(cmd, desc->its_mapd_cmd.valid);
+
+    its_fixup_cmd(cmd);
+
+    return desc->its_mapd_cmd.dev->collection;
+}
+
+static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
+                                                 struct its_cmd_desc *desc)
+{
+    its_encode_cmd(cmd, GITS_CMD_MAPC);
+    its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id);
+    its_encode_target(cmd, desc->its_mapc_cmd.col->target_address);
+    its_encode_valid(cmd, desc->its_mapc_cmd.valid);
+
+    its_fixup_cmd(cmd);
+
+    return desc->its_mapc_cmd.col;
+}
+
+static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd,
+                                                  struct its_cmd_desc *desc)
+{
+    its_encode_cmd(cmd, GITS_CMD_MAPVI);
+    its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id);
+    its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id);
+    its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id);
+    its_encode_collection(cmd, desc->its_mapvi_cmd.dev->collection->col_id);
+
+    its_fixup_cmd(cmd);
+
+    return desc->its_mapvi_cmd.dev->collection;
+}
+
+static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
+                                                 struct its_cmd_desc *desc)
+{
+    its_encode_cmd(cmd, GITS_CMD_MOVI);
+    its_encode_devid(cmd, desc->its_movi_cmd.dev->device_id);
+    its_encode_event_id(cmd, desc->its_movi_cmd.id);
+    its_encode_collection(cmd, desc->its_movi_cmd.col->col_id);
+
+    its_fixup_cmd(cmd);
+
+    return desc->its_movi_cmd.dev->collection;
+}
+
+static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
+                                                    struct its_cmd_desc *desc)
+{
+    its_encode_cmd(cmd, GITS_CMD_DISCARD);
+    its_encode_devid(cmd, desc->its_discard_cmd.dev->device_id);
+    its_encode_event_id(cmd, desc->its_discard_cmd.event_id);
+
+    its_fixup_cmd(cmd);
+
+    return desc->its_discard_cmd.dev->collection;
+}
+
+static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
+                                                struct its_cmd_desc *desc)
+{
+    its_encode_cmd(cmd, GITS_CMD_INV);
+    its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id);
+    its_encode_event_id(cmd, desc->its_inv_cmd.event_id);
+
+    its_fixup_cmd(cmd);
+
+    return desc->its_inv_cmd.dev->collection;
+}
+
+static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
+                                                   struct its_cmd_desc *desc)
+{
+    its_encode_cmd(cmd, GITS_CMD_INVALL);
+    its_encode_collection(cmd, desc->its_mapc_cmd.col->col_id);
+
+    its_fixup_cmd(cmd);
+
+    return NULL;
+}
+
+static u64 its_cmd_ptr_to_offset(struct its_node *its,
+                                 struct its_cmd_block *ptr)
+{
+    return (ptr - its->cmd_base) * sizeof(*ptr);
+}
+
+static int its_queue_full(struct its_node *its)
+{
+    int widx;
+    int ridx;
+
+    widx = its->cmd_write - its->cmd_base;
+    ridx = readl_relaxed(its->base + GITS_CREADR) / sizeof(struct its_cmd_block);
+
+    /* This is incredibly unlikely to happen, unless the ITS locks up. */
+    if (((widx + 1) % ITS_CMD_QUEUE_NR_ENTRIES) == ridx)
+        return 1;
+
+    return 0;
+}
+
+static struct its_cmd_block *its_allocate_entry(struct its_node *its)
+{
+    struct its_cmd_block *cmd;
+    u32 count = 1000000;    /* 1s! */
+
+    while (its_queue_full(its)) {
+        count--;
+        if (!count) {
+            pr_err_ratelimited("ITS queue not draining\n");
+            return NULL;
+        }
+        cpu_relax();
+        udelay(1);
+    }
+
+    cmd = its->cmd_write++;
+
+    /* Handle queue wrapping */
+    if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES))
+        its->cmd_write = its->cmd_base;
+
+    return cmd;
+}
+
+static struct its_cmd_block *its_post_commands(struct its_node *its)
+{
+    u64 wr = its_cmd_ptr_to_offset(its, its->cmd_write);
+
+    writel_relaxed(wr, its->base + GITS_CWRITER);
+
+    return its->cmd_write;
+}
+
+static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
+{
+    /*
+     * Make sure the commands written to memory are observable by
+     * the ITS.
+     */
+    if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING)
+        __flush_dcache_area(cmd, sizeof(*cmd));
+    else
+        dsb(ishst);
+}
+
+static void its_wait_for_range_completion(struct its_node *its,
+                                          struct its_cmd_block *from,
+                                          struct its_cmd_block *to)
+{
+    u64 rd_idx, from_idx, to_idx;
+    u32 count = 1000000;    /* 1s! */
+
+    from_idx = its_cmd_ptr_to_offset(its, from);
+    to_idx = its_cmd_ptr_to_offset(its, to);
+
+    while (1) {
+        rd_idx = readl_relaxed(its->base + GITS_CREADR);
+        if (rd_idx >= to_idx || rd_idx < from_idx)
+            break;
+
+        count--;
+        if (!count) {
+            pr_err_ratelimited("ITS queue timeout\n");
+            return;
+        }
+        cpu_relax();
+        udelay(1);
+    }
+}
+
+static void its_send_single_command(struct its_node *its,
+                                    its_cmd_builder_t builder,
+                                    struct its_cmd_desc *desc)
+{
+    struct its_cmd_block *cmd, *sync_cmd, *next_cmd;
+    struct its_collection *sync_col;
+
+    raw_spin_lock(&its->lock);
+
+    cmd = its_allocate_entry(its);
+    if (!cmd) {        /* We're soooooo screewed... */
+        pr_err_ratelimited("ITS can't allocate, dropping command\n");
+        raw_spin_unlock(&its->lock);
+        return;
+    }
+    sync_col = builder(cmd, desc);
+    its_flush_cmd(its, cmd);
+
+    if (sync_col) {
+        sync_cmd = its_allocate_entry(its);
+        if (!sync_cmd) {
+            pr_err_ratelimited("ITS can't SYNC, skipping\n");
+            goto post;
+        }
+        its_encode_cmd(sync_cmd, GITS_CMD_SYNC);
+        its_encode_target(sync_cmd, sync_col->target_address);
+        its_fixup_cmd(sync_cmd);
+        its_flush_cmd(its, sync_cmd);
+    }
+
+post:
+    next_cmd = its_post_commands(its);
+    raw_spin_unlock(&its->lock);
+
+    its_wait_for_range_completion(its, cmd, next_cmd);
+}
+
+static void its_send_inv(struct its_device *dev, u32 event_id)
+{
+    struct its_cmd_desc desc;
+
+    desc.its_inv_cmd.dev = dev;
+    desc.its_inv_cmd.event_id = event_id;
+
+    its_send_single_command(dev->its, its_build_inv_cmd, &desc);
+}
+
+static void its_send_mapd(struct its_device *dev, int valid)
+{
+    struct its_cmd_desc desc;
+
+    desc.its_mapd_cmd.dev = dev;
+    desc.its_mapd_cmd.valid = !!valid;
+
+    its_send_single_command(dev->its, its_build_mapd_cmd, &desc);
+}
+
+static void its_send_mapc(struct its_node *its, struct its_collection *col,
+              int valid)
+{
+    struct its_cmd_desc desc;
+
+    desc.its_mapc_cmd.col = col;
+    desc.its_mapc_cmd.valid = !!valid;
+
+    its_send_single_command(its, its_build_mapc_cmd, &desc);
+}
+
+static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id)
+{
+    struct its_cmd_desc desc;
+
+    desc.its_mapvi_cmd.dev = dev;
+    desc.its_mapvi_cmd.phys_id = irq_id;
+    desc.its_mapvi_cmd.event_id = id;
+
+    its_send_single_command(dev->its, its_build_mapvi_cmd, &desc);
+}
+
+static void its_send_movi(struct its_device *dev,
+              struct its_collection *col, u32 id)
+{
+    struct its_cmd_desc desc;
+
+    desc.its_movi_cmd.dev = dev;
+    desc.its_movi_cmd.col = col;
+    desc.its_movi_cmd.id = id;
+
+    its_send_single_command(dev->its, its_build_movi_cmd, &desc);
+}
+
+static void its_send_discard(struct its_device *dev, u32 id)
+{
+    struct its_cmd_desc desc;
+
+    desc.its_discard_cmd.dev = dev;
+    desc.its_discard_cmd.event_id = id;
+
+    its_send_single_command(dev->its, its_build_discard_cmd, &desc);
+}
+
+static void its_send_invall(struct its_node *its, struct its_collection *col)
+{
+    struct its_cmd_desc desc;
+
+    desc.its_invall_cmd.col = col;
+
+    its_send_single_command(its, its_build_invall_cmd, &desc);
+}
+
+/*
+ * irqchip functions - assumes MSI, mostly.
+ */
+
+static void lpi_set_config(struct its_device *its_dev, u32 hwirq,
+               u32 id, int enable)
+{
+    u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192;
+
+    if (enable)
+        *cfg |= LPI_PROP_ENABLED;
+    else
+        *cfg &= ~LPI_PROP_ENABLED;
+
+    /*
+     * Make the above write visible to the redistributors.
+     * And yes, we're flushing exactly: One. Single. Byte.
+     * Humpf...
+     */
+    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
+        __flush_dcache_area(cfg, sizeof(*cfg));
+    else
+        dsb(ishst);
+    its_send_inv(its_dev, id);
+}
+
+static inline u16 its_msi_get_entry_nr(struct msi_desc *desc)
+{
+    return desc->msi_attrib.entry_nr;
+}
+
+static void its_mask_irq(struct irq_data *d)
+{
+    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
+    u32 id;
+
+    /* If MSI, propagate the mask to the RC */
+    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
+        id = its_msi_get_entry_nr(d->msi_desc);
+        mask_msi_irq(d);
+    } else {
+        id = d->hwirq;
+    }
+
+    lpi_set_config(its_dev, d->hwirq, id, 0);
+}
+
+static void its_unmask_irq(struct irq_data *d)
+{
+    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
+    u32 id;
+
+    /* If MSI, propagate the unmask to the RC */
+    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
+        id = its_msi_get_entry_nr(d->msi_desc);
+        unmask_msi_irq(d);
+    } else {
+        id = d->hwirq;
+    }
+
+    lpi_set_config(its_dev, d->hwirq, id, 1);
+}
+
+static void its_eoi_irq(struct irq_data *d)
+{
+    gic_write_eoir(d->hwirq);
+}
+
+static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
+                            bool force)
+{
+    unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
+    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
+    struct its_collection *target_col;
+    u32 id;
+
+    if (cpu >= nr_cpu_ids)
+        return -EINVAL;
+
+    target_col = &its_dev->its->collections[cpu];
+    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc)
+        id = its_msi_get_entry_nr(d->msi_desc);
+    else
+        id = d->hwirq;
+    its_send_movi(its_dev, target_col, id);
+    its_dev->collection = target_col;
+
+    return IRQ_SET_MASK_OK;
+}
+
+static struct irq_chip its_irq_chip = {
+    .name            = "ITS",
+    .irq_mask        = its_mask_irq,
+    .irq_unmask        = its_unmask_irq,
+    .irq_eoi        = its_eoi_irq,
+    .irq_set_affinity    = its_set_affinity,
+};
+
+/*
+ * How we allocate LPIs:
+ *
+ * The GIC has id_bits bits for interrupt identifiers. From there, we
+ * must subtract 8192 which are reserved for SGIs/PPIs/SPIs. Then, as
+ * we allocate LPIs by chunks of 32, we can shift the whole thing by 5
+ * bits to the right.
+ *
+ * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
+ */
+#define IRQS_PER_CHUNK_SHIFT    5
+#define IRQS_PER_CHUNK        (1 << IRQS_PER_CHUNK_SHIFT)
+
+static unsigned long *lpi_bitmap;
+static u32 lpi_chunks;
+static DEFINE_SPINLOCK(lpi_lock);
+
+static int its_lpi_to_chunk(int lpi)
+{
+    return (lpi - 8192) >> IRQS_PER_CHUNK_SHIFT;
+}
+
+static int its_chunk_to_lpi(int chunk)
+{
+    return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
+}
+
+static int its_lpi_init(u32 id_bits)
+{
+    lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
+
+    lpi_bitmap = kzalloc(BITS_TO_LONGS(lpi_chunks) * sizeof(long),
+                 GFP_KERNEL);
+    if (!lpi_bitmap) {
+        lpi_chunks = 0;
+        return -ENOMEM;
+    }
+
+    pr_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
+    return 0;
+}
+
+static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)
+{
+    unsigned long *bitmap = NULL;
+    int chunk_id;
+    int nr_chunks;
+    int i;
+
+    nr_chunks = DIV_ROUND_UP(nr_irqs, IRQS_PER_CHUNK);
+
+    spin_lock(&lpi_lock);
+
+    do {
+        chunk_id = bitmap_find_next_zero_area(lpi_bitmap, lpi_chunks,
+                                              0, nr_chunks, 0);
+        if (chunk_id < lpi_chunks)
+            break;
+
+        nr_chunks--;
+    } while (nr_chunks > 0);
+
+    if (!nr_chunks)
+        goto out;
+
+    bitmap = kzalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long),
+             GFP_ATOMIC);
+    if (!bitmap)
+        goto out;
+
+    for (i = 0; i < nr_chunks; i++)
+        set_bit(chunk_id + i, lpi_bitmap);
+
+    *base = its_chunk_to_lpi(chunk_id);
+    *nr_ids = nr_chunks * IRQS_PER_CHUNK;
+
+out:
+    spin_unlock(&lpi_lock);
+
+    return bitmap;
+}
+
+static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
+{
+    int lpi;
+
+    spin_lock(&lpi_lock);
+
+    for (lpi = base; lpi < (base + nr_ids); lpi += IRQS_PER_CHUNK) {
+        int chunk = its_lpi_to_chunk(lpi);
+        BUG_ON(chunk > lpi_chunks);
+        if (test_bit(chunk, lpi_bitmap)) {
+            clear_bit(chunk, lpi_bitmap);
+        } else {
+            pr_err("Bad LPI chunk %d\n", chunk);
+        }
+    }
+
+    spin_unlock(&lpi_lock);
+
+    kfree(bitmap);
+}
+
+/*
+ * We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to
+ * deal with (one configuration byte per interrupt). PENDBASE has to
+ * be 64kB aligned (one bit per LPI, plus 8192 bits for SPI/PPI/SGI).
+ */
+#define LPI_PROPBASE_SZ        SZ_64K
+#define LPI_PENDBASE_SZ        (LPI_PROPBASE_SZ / 8 + SZ_1K)
+
+/*
+ * This is how many bits of ID we need, including the useless ones.
+ */
+#define LPI_NRBITS        ilog2(LPI_PROPBASE_SZ + SZ_8K)
+
+#define LPI_PROP_DEFAULT_PRIO    0xa0
+
+static int __init its_alloc_lpi_tables(void)
+{
+    phys_addr_t paddr;
+
+    gic_rdists->prop_page = alloc_pages(GFP_NOWAIT,
+                       get_order(LPI_PROPBASE_SZ));
+    if (!gic_rdists->prop_page) {
+        pr_err("Failed to allocate PROPBASE\n");
+        return -ENOMEM;
+    }
+
+    paddr = page_to_phys(gic_rdists->prop_page);
+    pr_info("GIC: using LPI property table @%pa\n", &paddr);
+
+    /* Priority 0xa0, Group-1, disabled */
+    memset(page_address(gic_rdists->prop_page),
+           LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1,
+           LPI_PROPBASE_SZ);
+
+    /* Make sure the GIC will observe the written configuration */
+    __flush_dcache_area(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ);
+
+    return 0;
+}
+
+static const char *its_base_type_string[] = {
+    [GITS_BASER_TYPE_DEVICE]    = "Devices",
+    [GITS_BASER_TYPE_VCPU]        = "Virtual CPUs",
+    [GITS_BASER_TYPE_CPU]        = "Physical CPUs",
+    [GITS_BASER_TYPE_COLLECTION]    = "Interrupt Collections",
+    [GITS_BASER_TYPE_RESERVED5]     = "Reserved (5)",
+    [GITS_BASER_TYPE_RESERVED6]     = "Reserved (6)",
+    [GITS_BASER_TYPE_RESERVED7]     = "Reserved (7)",
+};
+
+static void its_free_tables(struct its_node *its)
+{
+    int i;
+
+    for (i = 0; i < GITS_BASER_NR_REGS; i++) {
+        if (its->tables[i]) {
+            free_page((unsigned long)its->tables[i]);
+            its->tables[i] = NULL;
+        }
+    }
+}
+
+static int its_alloc_tables(struct its_node *its)
+{
+    int err;
+    int i;
+    int psz = SZ_64K;
+    u64 shr = GITS_BASER_InnerShareable;
+    u64 typer = readq_relaxed(its->base + GITS_TYPER);
+    u64 max_devices, max_ittsize;
+
+    max_devices = 1ULL << (((typer >> 13) & 0x1f) + 1);
+    max_ittsize = ((typer >> 4) & 0xf) + 1;
+    max_ittsize *= max_devices;
+
+    for (i = 0; i < GITS_BASER_NR_REGS; i++) {
+        u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
+        u64 type = GITS_BASER_TYPE(val);
+        u64 entry_size = GITS_BASER_ENTRY_SIZE(val);
+        u64 tmp;
+        void *base;
+
+        if (type == GITS_BASER_TYPE_NONE)
+            continue;
+
+        base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(max_ittsize));
+        if (!base) {
+            err = -ENOMEM;
+            goto out_free;
+        }
+
+
+        its->tables[i] = base;
+
+retry_baser:
+        val = (virt_to_phys(base)                                |
+               (type << GITS_BASER_TYPE_SHIFT)                   |
+               ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) |
+               GITS_BASER_WaWb                                   |
+               shr                                               |
+               GITS_BASER_VALID);
+
+        switch (psz) {
+        case SZ_4K:
+            val |= GITS_BASER_PAGE_SIZE_4K;
+            break;
+        case SZ_16K:
+            val |= GITS_BASER_PAGE_SIZE_16K;
+            break;
+        case SZ_64K:
+            val |= GITS_BASER_PAGE_SIZE_64K;
+            break;
+        }
+
+        val |= ((max_ittsize / psz) - 1) & 0xffUL;
+        writeq_relaxed(val, its->base + GITS_BASER + i * 8);
+
+        tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
+
+        if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) {
+            /*
+             * Shareability didn't stick. Just use
+             * whatever the read reported, which is likely
+             * to be the only thing this redistributor
+             * supports.
+             */
+            shr = tmp & GITS_BASER_SHAREABILITY_MASK;
+            goto retry_baser;
+        }
+
+        if ((val ^ tmp) & GITS_BASER_PAGE_SIZE_MASK) {
+            /*
+             * Page size didn't stick. Let's try a smaller
+             * size and retry. If we reach 4K, then
+             * something is horribly wrong...
+             */
+            switch (psz) {
+            case SZ_16K:
+                psz = SZ_4K;
+                goto retry_baser;
+            case SZ_64K:
+                psz = SZ_16K;
+                goto retry_baser;
+            }
+        }
+
+        /* skip comparing cacheability feilds as they are implemenations
+         * defined.
+         */
+        val = val << 5;
+        tmp = tmp << 5;
+
+        if (val != tmp) {
+            pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n",
+                   its->msi_chip.of_node->full_name, i,
+                   (unsigned long) val, (unsigned long) tmp);
+            err = -ENXIO;
+            goto out_free;
+        }
+
+        pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
+            (int)(PAGE_SIZE / entry_size),
+            its_base_type_string[type],
+            (unsigned long)virt_to_phys(base),
+            psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
+    }
+
+    return 0;
+
+out_free:
+    its_free_tables(its);
+
+    return err;
+}
+
+static int its_alloc_collections(struct its_node *its)
+{
+    its->collections = kzalloc(nr_cpu_ids * sizeof(*its->collections),
+                   GFP_KERNEL);
+    if (!its->collections)
+        return -ENOMEM;
+
+    return 0;
+}
+
+static void its_cpu_init_lpis(void)
+{
+    void __iomem *rbase = gic_data_rdist_rd_base();
+    struct page *pend_page;
+    u64 val, tmp;
+
+    /* If we didn't allocate the pending table yet, do it now */
+    pend_page = gic_data_rdist()->pend_page;
+    if (!pend_page) {
+        phys_addr_t paddr;
+        /*
+         * The pending pages have to be at least 64kB aligned,
+         * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below.
+         */
+        pend_page = alloc_pages(GFP_NOWAIT | __GFP_ZERO,
+                                get_order(max(LPI_PENDBASE_SZ, SZ_64K)));
+        if (!pend_page) {
+            pr_err("Failed to allocate PENDBASE for CPU%d\n",
+                   smp_processor_id());
+            return;
+        }
+
+        /* Make sure the GIC will observe the zero-ed page */
+        __flush_dcache_area(page_address(pend_page), LPI_PENDBASE_SZ);
+
+        paddr = page_to_phys(pend_page);
+        pr_info("CPU%d: using LPI pending table @%pa\n",
+            smp_processor_id(), &paddr);
+        gic_data_rdist()->pend_page = pend_page;
+    }
+
+    /* Disable LPIs */
+    val = readl_relaxed(rbase + GICR_CTLR);
+    val &= ~GICR_CTLR_ENABLE_LPIS;
+    writel_relaxed(val, rbase + GICR_CTLR);
+
+    /*
+     * Make sure any change to the table is observable by the GIC.
+     */
+    dsb(sy);
+
+    /* set PROPBASE */
+    val = (page_to_phys(gic_rdists->prop_page) |
+           GICR_PROPBASER_InnerShareable       |
+           GICR_PROPBASER_WaWb                 |
+           ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK));
+
+    writeq_relaxed(val, rbase + GICR_PROPBASER);
+    tmp = readq_relaxed(rbase + GICR_PROPBASER);
+
+    if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
+        pr_info_once("GIC: using cache flushing for LPI property table\n");
+        gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING;
+    }
+
+    /* set PENDBASE */
+    val = (page_to_phys(pend_page)       |
+           GICR_PROPBASER_InnerShareable |
+           GICR_PROPBASER_WaWb);
+
+    writeq_relaxed(val, rbase + GICR_PENDBASER);
+
+    /* Enable LPIs */
+    val = readl_relaxed(rbase + GICR_CTLR);
+    val |= GICR_CTLR_ENABLE_LPIS;
+    writel_relaxed(val, rbase + GICR_CTLR);
+
+    /* Make sure the GIC has seen the above */
+    dsb(sy);
+}
+
+static void its_cpu_init_collection(void)
+{
+    struct its_node *its;
+    int cpu;
+
+    spin_lock(&its_lock);
+    cpu = smp_processor_id();
+
+    list_for_each_entry(its, &its_nodes, entry) {
+        u64 target;
+
+        /*
+         * We now have to bind each collection to its target
+         * redistributor.
+         */
+        if (readq_relaxed(its->base + GITS_TYPER) & GITS_TYPER_PTA) {
+            /*
+             * This ITS wants the physical address of the
+             * redistributor.
+             */
+            target = gic_data_rdist()->phys_base;
+        } else {
+            /*
+             * This ITS wants a linear CPU number.
+             */
+            target = readq_relaxed(gic_data_rdist_rd_base() + GICR_TYPER);
+            target = GICR_TYPER_CPU_NUMBER(target);
+        }
+
+        /* Perform collection mapping */
+        its->collections[cpu].target_address = target;
+        its->collections[cpu].col_id = cpu;
+
+        its_send_mapc(its, &its->collections[cpu], 1);
+        its_send_invall(its, &its->collections[cpu]);
+    }
+
+    spin_unlock(&its_lock);
+}
+
+static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
+{
+    struct its_device *its_dev = NULL, *tmp;
+
+    raw_spin_lock(&its->lock);
+
+    list_for_each_entry(tmp, &its->its_device_list, entry) {
+        if (tmp->device_id == dev_id) {
+            its_dev = tmp;
+            break;
+        }
+    }
+
+    raw_spin_unlock(&its->lock);
+
+    return its_dev;
+}
+
+static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
+                                            int nvecs)
+{
+    struct its_device *dev;
+    unsigned long *lpi_map;
+    void *itt;
+    int lpi_base;
+    int nr_lpis;
+    int cpu;
+    int sz;
+
+    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+    sz = nvecs * its->ite_size;
+    sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
+    itt = kmalloc(sz, GFP_KERNEL);
+    lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
+
+    if (!dev || !itt || !lpi_map) {
+        kfree(dev);
+        kfree(itt);
+        kfree(lpi_map);
+        return NULL;
+    }
+
+    dev->its = its;
+    dev->itt = itt;
+    dev->nr_ites = nvecs;
+    dev->lpi_map = lpi_map;
+    dev->lpi_base = lpi_base;
+    dev->nr_lpis = nr_lpis;
+    dev->device_id = dev_id;
+    INIT_LIST_HEAD(&dev->entry);
+
+    raw_spin_lock(&its->lock);
+    list_add(&dev->entry, &its->its_device_list);
+    raw_spin_unlock(&its->lock);
+
+    /* Bind the device to the first possible CPU */
+    cpu = cpumask_first(cpu_online_mask);
+    dev->collection = &its->collections[cpu];
+
+    /* Map device to its ITT */
+    its_send_mapd(dev, 1);
+
+    return dev;
+}
+
+static void its_free_device(struct its_device *its_dev)
+{
+    raw_spin_lock(&its_dev->its->lock);
+    list_del(&its_dev->entry);
+    raw_spin_unlock(&its_dev->its->lock);
+    kfree(its_dev->itt);
+    kfree(its_dev);
+}
+
+static int its_alloc_device_irq(struct its_device *dev, u32 id,
+                                int *hwirq, unsigned int *irq)
+{
+    int idx;
+
+    idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis);
+    if (idx == dev->nr_lpis)
+        return -ENOSPC;
+
+    *hwirq = dev->lpi_base + idx;
+    *irq = irq_create_mapping(lpi_domain, *hwirq);
+    if (!*irq)
+        return -ENOSPC;    /* Don't kill the device, though */
+
+    set_bit(idx, dev->lpi_map);
+
+    /* Map the GIC irq ID to the device */
+    its_send_mapvi(dev, *hwirq, id);
+
+    return 0;
+}
+
+
+
+static int its_msi_get_vec_count(struct pci_dev *pdev, struct msi_desc *desc)
+{
+#ifdef CONFIG_PCI_MSI
+    if (desc->msi_attrib.is_msix)
+        return pci_msix_vec_count(pdev);
+    else
+        return pci_msi_vec_count(pdev);
+#else
+    return -EINVAL;
+#endif
+}
+
+int pci_requester_id(struct pci_dev *dev);
+static int its_msi_setup_irq(struct msi_chip *chip,
+                             struct pci_dev *pdev,
+                             struct msi_desc *desc)
+{
+    struct its_node *its = container_of(chip, struct its_node, msi_chip);
+    struct its_device *its_dev;
+    struct msi_msg msg;
+    unsigned int irq;
+    u64 addr;
+    int hwirq;
+    int err;
+    u32 dev_id = pci_requester_id(pdev);
+    u32 vec_nr;
+
+    its_dev = its_find_device(its, dev_id);
+    if (!its_dev) {
+        int nvec = its_msi_get_vec_count(pdev, desc);
+        if (WARN_ON(nvec <= 0))
+            return nvec;
+        its_dev = its_create_device(its, dev_id, nvec);
+    }
+    if (!its_dev)
+        return -ENOMEM;
+    vec_nr = its_msi_get_entry_nr(desc);
+    err = its_alloc_device_irq(its_dev, vec_nr, &hwirq, &irq);
+    if (err)
+        return err;
+
+    irq_set_msi_desc(irq, desc);
+    irq_set_handler_data(irq, its_dev);
+
+    addr = its->phys_base + GITS_TRANSLATER;
+
+    msg.address_lo        = (u32)addr;
+    msg.address_hi        = (u32)(addr >> 32);
+    msg.data        = vec_nr;
+
+    write_msi_msg(irq, &msg);
+    return 0;
+}
+
+static void its_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+{
+    struct irq_data *d = irq_get_irq_data(irq);
+    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
+
+    BUG_ON(d->hwirq < its_dev->lpi_base ||        /* OMG! */
+           d->hwirq > (its_dev->lpi_base + its_dev->nr_lpis));
+
+    /* Stop the delivery of interrupts */
+    its_send_discard(its_dev, its_msi_get_entry_nr(d->msi_desc));
+
+    /* Mark interrupt index as unused, and clear the mapping */
+    clear_bit(d->hwirq - its_dev->lpi_base, its_dev->lpi_map);
+    irq_dispose_mapping(irq);
+
+    /* If all interrupts have been freed, start mopping the floor */
+    if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
+        its_lpi_free(its_dev->lpi_map,
+                     its_dev->lpi_base,
+                     its_dev->nr_lpis);
+
+        /* Unmap device/itt */
+        its_send_mapd(its_dev, 0);
+        its_free_device(its_dev);
+    }
+}
+
+static int its_probe(struct device_node *node)
+{
+    struct resource res;
+    struct its_node *its;
+    void __iomem *its_base;
+    u32 val;
+    u64 baser, tmp;
+    int err;
+
+    err = of_address_to_resource(node, 0, &res);
+    if (err) {
+        pr_warn("%s: no regs?\n", node->full_name);
+        return -ENXIO;
+    }
+
+    its_base = ioremap(res.start, resource_size(&res));
+    if (!its_base) {
+        pr_warn("%s: unable to map registers\n", node->full_name);
+        return -ENOMEM;
+    }
+
+    val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
+    if (val != 0x30 && val != 0x40) {
+        pr_warn("%s: no ITS detected, giving up\n", node->full_name);
+        err = -ENODEV;
+        goto out_unmap;
+    }
+
+    pr_info("ITS: %s\n", node->full_name);
+
+    its = kzalloc(sizeof(*its), GFP_KERNEL);
+    if (!its) {
+        err = -ENOMEM;
+        goto out_unmap;
+    }
+
+    raw_spin_lock_init(&its->lock);
+    INIT_LIST_HEAD(&its->entry);
+    INIT_LIST_HEAD(&its->its_device_list);
+    its->base = its_base;
+    its->phys_base = res.start;
+    its->msi_chip.of_node = node;
+    its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
+
+    its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
+    if (!its->cmd_base) {
+        err = -ENOMEM;
+        goto out_free_its;
+    }
+    its->cmd_write = its->cmd_base;
+
+    err = its_alloc_tables(its);
+    if (err)
+        goto out_free_cmd;
+
+    err = its_alloc_collections(its);
+    if (err)
+        goto out_free_tables;
+
+    baser = (virt_to_phys(its->cmd_base)    |
+             GITS_CBASER_WaWb               |
+             GITS_CBASER_InnerShareable     |
+             (ITS_CMD_QUEUE_SZ / SZ_4K - 1) |
+             GITS_CBASER_VALID);
+
+    writeq_relaxed(baser, its->base + GITS_CBASER);
+    tmp = readq_relaxed(its->base + GITS_CBASER);
+/*    writeq_relaxed(0, its->base + GITS_CWRITER); */
+    writel_relaxed(1, its->base + GITS_CTLR);
+
+    if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) {
+        pr_info("ITS: using cache flushing for cmd queue\n");
+        its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
+    }
+
+    spin_lock(&its_lock);
+    list_add(&its->entry, &its_nodes);
+    spin_unlock(&its_lock);
+
+    if (IS_ENABLED(CONFIG_PCI_MSI) && /* Remove this once we have PCI... */
+        of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
+        its->msi_chip.setup_irq        = its_msi_setup_irq;
+        its->msi_chip.teardown_irq    = its_msi_teardown_irq;
+
+        err = of_pci_msi_chip_add(&its->msi_chip);
+    }
+
+    return err;
+
+out_free_tables:
+    its_free_tables(its);
+out_free_cmd:
+    kfree(its->cmd_base);
+out_free_its:
+    kfree(its);
+out_unmap:
+    iounmap(its_base);
+    pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
+    return err;
+}
+
+static bool gic_rdists_supports_plpis(void)
+{
+    return !!(readl_relaxed(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
+}
+
+int its_cpu_init(void)
+{
+    if (!gic_rdists_supports_plpis()) {
+        pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
+        return -ENXIO;
+    }
+
+    if (!list_empty(&its_nodes)) {
+        its_cpu_init_lpis();
+        its_cpu_init_collection();
+    }
+
+    return 0;
+}
+
+static struct of_device_id its_device_id[] = {
+    {    .compatible    = "arm,gic-v3-its",    },
+    {},
+};
+
+struct irq_chip *its_init(struct device_node *node, struct rdists *rdists,
+                          struct irq_domain *domain)
+{
+    struct device_node *np;
+
+    for (np = of_find_matching_node(node, its_device_id); np;
+         np = of_find_matching_node(np, its_device_id)) {
+        its_probe(np);
+    }
+
+    if (list_empty(&its_nodes)) {
+        pr_info("ITS: No ITS available, not enabling LPIs\n");
+        return NULL;
+    }
+
+    gic_rdists = rdists;
+    gic_root_node = node;
+    lpi_domain = domain;
+
+    its_alloc_lpi_tables();
+    its_lpi_init(rdists->id_bits);
+
+    return &its_irq_chip;
+}
-- 
1.7.9.5

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

* [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 01/19] xen/arm: add linked list apis vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-13 11:46   ` Julien Grall
  2015-03-02 12:30 ` [RFC PATCH 04/19] xen/arm: its: Move ITS command encode helper functions vijay.kilari
                   ` (17 subsequent siblings)
  20 siblings, 1 reply; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

This patch just makes ITS driver taken from linux
compiles in xen environment.

The following changes are done
 - memory allocation apis are changed
 - raw spin lock api's changed to normal spin lock api's
 - debug prints changed to xen debug prints
 - remove msi chip functions to setup_irq and teardown_irq
 - linux irqchip functions are removed
 - updated gic_v3_defs.h file

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/Makefile             |    1 +
 xen/arch/arm/gic-v3-its.c         |  548 +++++++++++++------------------------
 xen/arch/arm/gic-v3.c             |    1 +
 xen/include/asm-arm/gic_v3_defs.h |  127 +++++++++
 4 files changed, 322 insertions(+), 355 deletions(-)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 41aba2e..f6eb834 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -13,6 +13,7 @@ obj-y += sysctl.o
 obj-y += domain_build.o
 obj-y += gic.o gic-v2.o
 obj-$(CONFIG_ARM_64) += gic-v3.o
+obj-$(CONFIG_ARM_64) += gic-v3-its.o
 obj-y += io.o
 obj-y += irq.o
 obj-y += kernel.o
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 28b72e4..cde0ec0 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -2,6 +2,10 @@
  * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
  * Author: Marc Zyngier <marc.zyngier@arm.com>
  *
+ * Xen changes:
+ * Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
+ * Copyright (C) 2014, 2015 Cavium Inc.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -15,28 +19,40 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/bitmap.h>
-#include <linux/cpu.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/log2.h>
-#include <linux/mm.h>
-#include <linux/msi.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_pci.h>
-#include <linux/of_platform.h>
-#include <linux/percpu.h>
-#include <linux/slab.h>
-
-#include <linux/irqchip/arm-gic-v3.h>
-
-#include <asm/cacheflush.h>
-#include <asm/cputype.h>
-#include <asm/exception.h>
-
-#include "irqchip.h"
+#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/delay.h>
+#include <xen/device_tree.h>
+#include <xen/libfdt/libfdt.h>
+#include <xen/xmalloc.h>
+#include <xen/list.h>
+#include <xen/sizes.h>
+#include <asm/p2m.h>
+#include <asm/domain.h>
+#include <asm/io.h>
+#include <asm/device.h>
+#include <asm/gic.h>
+#include <asm/gic_v3_defs.h>
+
+#define its_print(lvl, fmt, ...)                                        \
+    printk(lvl "GIC-ITS:" fmt, ## __VA_ARGS__)
+
+#define its_err(fmt, ...) its_print(XENLOG_ERR, fmt, ## __VA_ARGS__)
+
+#define its_dbg(fmt, ...)                                             \
+    its_print(XENLOG_DEBUG, fmt, ## __VA_ARGS__)
+
+#define its_info(fmt, ...)                                            \
+    its_print(XENLOG_INFO, fmt, ## __VA_ARGS__)
+
+#define its_warn(fmt, ...)                                            \
+    its_print(XENLOG_WARNING, fmt, ## __VA_ARGS__)
 
 #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING        (1 << 0)
 
@@ -58,9 +74,8 @@ struct its_collection {
  * devices writing to it.
  */
 struct its_node {
-    raw_spinlock_t        lock;
+    spinlock_t        lock;
     struct                list_head entry;
-    struct msi_chip       msi_chip;
     void __iomem          *base;
     unsigned long         phys_base;
     struct its_cmd_block  *cmd_base;
@@ -92,12 +107,11 @@ struct its_device {
 
 static LIST_HEAD(its_nodes);
 static DEFINE_SPINLOCK(its_lock);
-static struct irq_domain  *lpi_domain;
-static struct device_node *gic_root_node;
-static struct rdists      *gic_rdists;
+static struct dt_device_node *gic_root_node;
+static struct rdist_prop  *gic_rdists;
 
-#define gic_data_rdist()        (raw_cpu_ptr(gic_rdists->rdist))
-#define gic_data_rdist_rd_base()    (gic_data_rdist()->rd_base)
+#define gic_data_rdist()              (per_cpu(rdist, smp_processor_id()))
+#define gic_data_rdist_rd_base()      (per_cpu(rdist, smp_processor_id()).rbase)
 
 /*
  * ITS command descriptors - parameters to be encoded in a command
@@ -228,10 +242,10 @@ static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
     unsigned long itt_addr;
-    u8 size = max(order_base_2(desc->its_mapd_cmd.dev->nr_ites), 1);
+    u8 size = max(fls(desc->its_mapd_cmd.dev->nr_ites) - 1, 1);
 
-    itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
-    itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
+    itt_addr = __pa(desc->its_mapd_cmd.dev->itt);
+    itt_addr = ((itt_addr) + (ITS_ITT_ALIGN - 1)) & ~(ITS_ITT_ALIGN - 1);
 
     its_encode_cmd(cmd, GITS_CMD_MAPD);
     its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id);
@@ -343,17 +357,23 @@ static int its_queue_full(struct its_node *its)
 static struct its_cmd_block *its_allocate_entry(struct its_node *its)
 {
     struct its_cmd_block *cmd;
-    u32 count = 1000000;    /* 1s! */
+    bool_t timeout = 0;
+    s_time_t deadline = NOW() + MILLISECS(1000);
 
     while (its_queue_full(its)) {
-        count--;
-        if (!count) {
-            pr_err_ratelimited("ITS queue not draining\n");
-            return NULL;
+       if ( NOW() > deadline )
+        {
+            timeout = 1;
+            break;
         }
         cpu_relax();
         udelay(1);
     }
+    if ( timeout )
+    {
+        its_err("ITS queue not draining\n");
+        return NULL;
+    }
 
     cmd = its->cmd_write++;
 
@@ -380,7 +400,7 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
      * the ITS.
      */
     if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING)
-        __flush_dcache_area(cmd, sizeof(*cmd));
+        clean_dcache_va_range(cmd, sizeof(*cmd));
     else
         dsb(ishst);
 }
@@ -390,7 +410,8 @@ static void its_wait_for_range_completion(struct its_node *its,
                                           struct its_cmd_block *to)
 {
     u64 rd_idx, from_idx, to_idx;
-    u32 count = 1000000;    /* 1s! */
+    bool_t timeout = 0;
+    s_time_t deadline = NOW() + MILLISECS(1000);
 
     from_idx = its_cmd_ptr_to_offset(its, from);
     to_idx = its_cmd_ptr_to_offset(its, to);
@@ -400,14 +421,16 @@ static void its_wait_for_range_completion(struct its_node *its,
         if (rd_idx >= to_idx || rd_idx < from_idx)
             break;
 
-        count--;
-        if (!count) {
-            pr_err_ratelimited("ITS queue timeout\n");
-            return;
+        if ( NOW() > deadline )
+        {
+            timeout = 1;
+            break;
         }
         cpu_relax();
         udelay(1);
     }
+    if ( timeout )
+        printk("ITS queue timeout\n");
 }
 
 static void its_send_single_command(struct its_node *its,
@@ -417,12 +440,12 @@ static void its_send_single_command(struct its_node *its,
     struct its_cmd_block *cmd, *sync_cmd, *next_cmd;
     struct its_collection *sync_col;
 
-    raw_spin_lock(&its->lock);
+    spin_lock(&its->lock);
 
     cmd = its_allocate_entry(its);
     if (!cmd) {        /* We're soooooo screewed... */
-        pr_err_ratelimited("ITS can't allocate, dropping command\n");
-        raw_spin_unlock(&its->lock);
+        its_err("ITS can't allocate, dropping command\n");
+        spin_unlock(&its->lock);
         return;
     }
     sync_col = builder(cmd, desc);
@@ -431,7 +454,7 @@ static void its_send_single_command(struct its_node *its,
     if (sync_col) {
         sync_cmd = its_allocate_entry(its);
         if (!sync_cmd) {
-            pr_err_ratelimited("ITS can't SYNC, skipping\n");
+            its_warn("ITS can't SYNC, skipping\n");
             goto post;
         }
         its_encode_cmd(sync_cmd, GITS_CMD_SYNC);
@@ -442,12 +465,12 @@ static void its_send_single_command(struct its_node *its,
 
 post:
     next_cmd = its_post_commands(its);
-    raw_spin_unlock(&its->lock);
+    spin_unlock(&its->lock);
 
     its_wait_for_range_completion(its, cmd, next_cmd);
 }
 
-static void its_send_inv(struct its_device *dev, u32 event_id)
+void its_send_inv(struct its_device *dev, u32 event_id)
 {
     struct its_cmd_desc desc;
 
@@ -489,7 +512,7 @@ static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id)
     its_send_single_command(dev->its, its_build_mapvi_cmd, &desc);
 }
 
-static void its_send_movi(struct its_device *dev,
+void its_send_movi(struct its_device *dev,
               struct its_collection *col, u32 id)
 {
     struct its_cmd_desc desc;
@@ -501,7 +524,7 @@ static void its_send_movi(struct its_device *dev,
     its_send_single_command(dev->its, its_build_movi_cmd, &desc);
 }
 
-static void its_send_discard(struct its_device *dev, u32 id)
+void its_send_discard(struct its_device *dev, u32 id)
 {
     struct its_cmd_desc desc;
 
@@ -521,104 +544,6 @@ static void its_send_invall(struct its_node *its, struct its_collection *col)
 }
 
 /*
- * irqchip functions - assumes MSI, mostly.
- */
-
-static void lpi_set_config(struct its_device *its_dev, u32 hwirq,
-               u32 id, int enable)
-{
-    u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192;
-
-    if (enable)
-        *cfg |= LPI_PROP_ENABLED;
-    else
-        *cfg &= ~LPI_PROP_ENABLED;
-
-    /*
-     * Make the above write visible to the redistributors.
-     * And yes, we're flushing exactly: One. Single. Byte.
-     * Humpf...
-     */
-    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
-        __flush_dcache_area(cfg, sizeof(*cfg));
-    else
-        dsb(ishst);
-    its_send_inv(its_dev, id);
-}
-
-static inline u16 its_msi_get_entry_nr(struct msi_desc *desc)
-{
-    return desc->msi_attrib.entry_nr;
-}
-
-static void its_mask_irq(struct irq_data *d)
-{
-    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
-    u32 id;
-
-    /* If MSI, propagate the mask to the RC */
-    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
-        id = its_msi_get_entry_nr(d->msi_desc);
-        mask_msi_irq(d);
-    } else {
-        id = d->hwirq;
-    }
-
-    lpi_set_config(its_dev, d->hwirq, id, 0);
-}
-
-static void its_unmask_irq(struct irq_data *d)
-{
-    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
-    u32 id;
-
-    /* If MSI, propagate the unmask to the RC */
-    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
-        id = its_msi_get_entry_nr(d->msi_desc);
-        unmask_msi_irq(d);
-    } else {
-        id = d->hwirq;
-    }
-
-    lpi_set_config(its_dev, d->hwirq, id, 1);
-}
-
-static void its_eoi_irq(struct irq_data *d)
-{
-    gic_write_eoir(d->hwirq);
-}
-
-static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
-                            bool force)
-{
-    unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
-    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
-    struct its_collection *target_col;
-    u32 id;
-
-    if (cpu >= nr_cpu_ids)
-        return -EINVAL;
-
-    target_col = &its_dev->its->collections[cpu];
-    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc)
-        id = its_msi_get_entry_nr(d->msi_desc);
-    else
-        id = d->hwirq;
-    its_send_movi(its_dev, target_col, id);
-    its_dev->collection = target_col;
-
-    return IRQ_SET_MASK_OK;
-}
-
-static struct irq_chip its_irq_chip = {
-    .name            = "ITS",
-    .irq_mask        = its_mask_irq,
-    .irq_unmask        = its_unmask_irq,
-    .irq_eoi        = its_eoi_irq,
-    .irq_set_affinity    = its_set_affinity,
-};
-
-/*
  * How we allocate LPIs:
  *
  * The GIC has id_bits bits for interrupt identifiers. From there, we
@@ -640,7 +565,7 @@ static int its_lpi_to_chunk(int lpi)
     return (lpi - 8192) >> IRQS_PER_CHUNK_SHIFT;
 }
 
-static int its_chunk_to_lpi(int chunk)
+int its_chunk_to_lpi(int chunk)
 {
     return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
 }
@@ -649,31 +574,29 @@ static int its_lpi_init(u32 id_bits)
 {
     lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
 
-    lpi_bitmap = kzalloc(BITS_TO_LONGS(lpi_chunks) * sizeof(long),
-                 GFP_KERNEL);
+    lpi_bitmap =  xzalloc_bytes(lpi_chunks / 8);
     if (!lpi_bitmap) {
         lpi_chunks = 0;
         return -ENOMEM;
     }
 
-    pr_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
+    its_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
     return 0;
 }
 
-static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)
+static unsigned long *its_lpi_alloc_chunks(int nr_irq, int *base, int *nr_ids)
 {
     unsigned long *bitmap = NULL;
     int chunk_id;
     int nr_chunks;
     int i;
 
-    nr_chunks = DIV_ROUND_UP(nr_irqs, IRQS_PER_CHUNK);
+    nr_chunks = DIV_ROUND_UP(nr_irq, IRQS_PER_CHUNK);
 
     spin_lock(&lpi_lock);
 
     do {
-        chunk_id = bitmap_find_next_zero_area(lpi_bitmap, lpi_chunks,
-                                              0, nr_chunks, 0);
+        chunk_id = find_next_zero_bit(lpi_bitmap, lpi_chunks, 0);
         if (chunk_id < lpi_chunks)
             break;
 
@@ -683,8 +606,7 @@ static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)
     if (!nr_chunks)
         goto out;
 
-    bitmap = kzalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long),
-             GFP_ATOMIC);
+    bitmap = xzalloc_bytes(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long));
     if (!bitmap)
         goto out;
 
@@ -700,7 +622,7 @@ out:
     return bitmap;
 }
 
-static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
+void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
 {
     int lpi;
 
@@ -712,13 +634,13 @@ static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
         if (test_bit(chunk, lpi_bitmap)) {
             clear_bit(chunk, lpi_bitmap);
         } else {
-            pr_err("Bad LPI chunk %d\n", chunk);
+            its_err("Bad LPI chunk %d\n", chunk);
         }
     }
 
     spin_unlock(&lpi_lock);
 
-    kfree(bitmap);
+    xfree(bitmap);
 }
 
 /*
@@ -732,31 +654,28 @@ static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
 /*
  * This is how many bits of ID we need, including the useless ones.
  */
-#define LPI_NRBITS        ilog2(LPI_PROPBASE_SZ + SZ_8K)
+#define LPI_NRBITS        (fls(LPI_PROPBASE_SZ + SZ_8K) - 1)
 
-#define LPI_PROP_DEFAULT_PRIO    0xa0
+#define LPI_PROP_DEFAULT_PRIO    0xa2
 
 static int __init its_alloc_lpi_tables(void)
 {
-    phys_addr_t paddr;
+    gic_rdists->prop_page = alloc_xenheap_pages(get_order_from_bytes(LPI_PROPBASE_SZ), 0);
 
-    gic_rdists->prop_page = alloc_pages(GFP_NOWAIT,
-                       get_order(LPI_PROPBASE_SZ));
     if (!gic_rdists->prop_page) {
-        pr_err("Failed to allocate PROPBASE\n");
+        its_err("Failed to allocate PROPBASE\n");
         return -ENOMEM;
     }
 
-    paddr = page_to_phys(gic_rdists->prop_page);
-    pr_info("GIC: using LPI property table @%pa\n", &paddr);
+    its_info("GIC: using LPI property table @%pa\n", gic_rdists->prop_page);
 
     /* Priority 0xa0, Group-1, disabled */
-    memset(page_address(gic_rdists->prop_page),
+    memset(gic_rdists->prop_page,
            LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1,
            LPI_PROPBASE_SZ);
 
     /* Make sure the GIC will observe the written configuration */
-    __flush_dcache_area(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ);
+    clean_dcache_va_range(gic_rdists->prop_page, LPI_PROPBASE_SZ);
 
     return 0;
 }
@@ -777,7 +696,7 @@ static void its_free_tables(struct its_node *its)
 
     for (i = 0; i < GITS_BASER_NR_REGS; i++) {
         if (its->tables[i]) {
-            free_page((unsigned long)its->tables[i]);
+            xfree(its->tables[i]);
             its->tables[i] = NULL;
         }
     }
@@ -806,17 +725,18 @@ static int its_alloc_tables(struct its_node *its)
         if (type == GITS_BASER_TYPE_NONE)
             continue;
 
-        base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(max_ittsize));
+        base = alloc_xenheap_pages(get_order_from_bytes(max_ittsize), 0);
         if (!base) {
             err = -ENOMEM;
             goto out_free;
         }
-
+        memset(base, 0, max_ittsize);
+        clear_page(base);
 
         its->tables[i] = base;
 
 retry_baser:
-        val = (virt_to_phys(base)                                |
+        val = (__pa(base)                                        |
                (type << GITS_BASER_TYPE_SHIFT)                   |
                ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) |
                GITS_BASER_WaWb                                   |
@@ -874,17 +794,16 @@ retry_baser:
         tmp = tmp << 5;
 
         if (val != tmp) {
-            pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n",
-                   its->msi_chip.of_node->full_name, i,
-                   (unsigned long) val, (unsigned long) tmp);
+            its_err("ITS: GITS_BASER%d doesn't stick: %lx %lx\n",
+                   i, (unsigned long) val, (unsigned long) tmp);
             err = -ENXIO;
             goto out_free;
         }
 
-        pr_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
+        its_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
             (int)(PAGE_SIZE / entry_size),
             its_base_type_string[type],
-            (unsigned long)virt_to_phys(base),
+            (unsigned long)__pa(base),
             psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT);
     }
 
@@ -898,8 +817,7 @@ out_free:
 
 static int its_alloc_collections(struct its_node *its)
 {
-    its->collections = kzalloc(nr_cpu_ids * sizeof(*its->collections),
-                   GFP_KERNEL);
+    its->collections = xzalloc_array(struct its_collection, nr_cpu_ids);
     if (!its->collections)
         return -ENOMEM;
 
@@ -909,32 +827,30 @@ static int its_alloc_collections(struct its_node *its)
 static void its_cpu_init_lpis(void)
 {
     void __iomem *rbase = gic_data_rdist_rd_base();
-    struct page *pend_page;
+    void *pend_page;
     u64 val, tmp;
 
     /* If we didn't allocate the pending table yet, do it now */
-    pend_page = gic_data_rdist()->pend_page;
+    pend_page = gic_data_rdist().pend_page;
     if (!pend_page) {
-        phys_addr_t paddr;
         /*
          * The pending pages have to be at least 64kB aligned,
          * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below.
          */
-        pend_page = alloc_pages(GFP_NOWAIT | __GFP_ZERO,
-                                get_order(max(LPI_PENDBASE_SZ, SZ_64K)));
+        pend_page = alloc_xenheap_pages(get_order_from_bytes(max(LPI_PENDBASE_SZ, SZ_64K)), 0);
         if (!pend_page) {
-            pr_err("Failed to allocate PENDBASE for CPU%d\n",
+            its_err("Failed to allocate PENDBASE for CPU%d\n",
                    smp_processor_id());
             return;
         }
 
+        memset(pend_page, 0, max(LPI_PENDBASE_SZ, SZ_64K));
         /* Make sure the GIC will observe the zero-ed page */
-        __flush_dcache_area(page_address(pend_page), LPI_PENDBASE_SZ);
+        clean_dcache_va_range(pend_page, LPI_PENDBASE_SZ);
 
-        paddr = page_to_phys(pend_page);
-        pr_info("CPU%d: using LPI pending table @%pa\n",
-            smp_processor_id(), &paddr);
-        gic_data_rdist()->pend_page = pend_page;
+        its_info("CPU%d: using LPI pending table @%pa\n",
+                 smp_processor_id(), pend_page);
+        gic_data_rdist().pend_page = pend_page;
     }
 
     /* Disable LPIs */
@@ -948,7 +864,7 @@ static void its_cpu_init_lpis(void)
     dsb(sy);
 
     /* set PROPBASE */
-    val = (page_to_phys(gic_rdists->prop_page) |
+    val = (__pa(gic_rdists->prop_page)         |
            GICR_PROPBASER_InnerShareable       |
            GICR_PROPBASER_WaWb                 |
            ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK));
@@ -957,12 +873,12 @@ static void its_cpu_init_lpis(void)
     tmp = readq_relaxed(rbase + GICR_PROPBASER);
 
     if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) {
-        pr_info_once("GIC: using cache flushing for LPI property table\n");
+        its_info("GIC: using cache flushing for LPI property table\n");
         gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING;
     }
 
     /* set PENDBASE */
-    val = (page_to_phys(pend_page)       |
+    val = (__pa(pend_page)               |
            GICR_PROPBASER_InnerShareable |
            GICR_PROPBASER_WaWb);
 
@@ -997,7 +913,7 @@ static void its_cpu_init_collection(void)
              * This ITS wants the physical address of the
              * redistributor.
              */
-            target = gic_data_rdist()->phys_base;
+            target = gic_data_rdist().phys_base;
         } else {
             /*
              * This ITS wants a linear CPU number.
@@ -1017,11 +933,11 @@ static void its_cpu_init_collection(void)
     spin_unlock(&its_lock);
 }
 
-static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
+struct its_device *its_find_device(struct its_node *its, u32 dev_id)
 {
     struct its_device *its_dev = NULL, *tmp;
 
-    raw_spin_lock(&its->lock);
+    spin_lock(&its->lock);
 
     list_for_each_entry(tmp, &its->its_device_list, entry) {
         if (tmp->device_id == dev_id) {
@@ -1030,13 +946,14 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
         }
     }
 
-    raw_spin_unlock(&its->lock);
+    spin_unlock(&its->lock);
 
     return its_dev;
 }
 
-static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
-                                            int nvecs)
+/* TODO: Removed static for compilation */
+struct its_device *its_create_device(struct its_node *its, u32 dev_id,
+                                     int nvecs)
 {
     struct its_device *dev;
     unsigned long *lpi_map;
@@ -1046,16 +963,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
     int cpu;
     int sz;
 
-    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+    dev = xzalloc(struct its_device);
     sz = nvecs * its->ite_size;
     sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
-    itt = kmalloc(sz, GFP_KERNEL);
+    itt = xzalloc_bytes(sz);
     lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
 
     if (!dev || !itt || !lpi_map) {
-        kfree(dev);
-        kfree(itt);
-        kfree(lpi_map);
+        xfree(dev);
+        xfree(itt);
+        xfree(lpi_map);
         return NULL;
     }
 
@@ -1068,12 +985,12 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
     dev->device_id = dev_id;
     INIT_LIST_HEAD(&dev->entry);
 
-    raw_spin_lock(&its->lock);
+    spin_lock(&its->lock);
     list_add(&dev->entry, &its->its_device_list);
-    raw_spin_unlock(&its->lock);
+    spin_unlock(&its->lock);
 
     /* Bind the device to the first possible CPU */
-    cpu = cpumask_first(cpu_online_mask);
+    cpu = cpumask_first(&cpu_online_map);
     dev->collection = &its->collections[cpu];
 
     /* Map device to its ITT */
@@ -1082,17 +999,18 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
     return dev;
 }
 
-static void its_free_device(struct its_device *its_dev)
+void its_free_device(struct its_device *its_dev)
 {
-    raw_spin_lock(&its_dev->its->lock);
+    spin_lock(&its_dev->its->lock);
     list_del(&its_dev->entry);
-    raw_spin_unlock(&its_dev->its->lock);
-    kfree(its_dev->itt);
-    kfree(its_dev);
+    spin_unlock(&its_dev->its->lock);
+    xfree(its_dev->itt);
+    xfree(its_dev);
 }
 
-static int its_alloc_device_irq(struct its_device *dev, u32 id,
-                                int *hwirq, unsigned int *irq)
+/* TODO: Removed static for compilation */
+int its_alloc_device_irq(struct its_device *dev, u32 id,
+                         int *hwirq, unsigned int *irq)
 {
     int idx;
 
@@ -1101,9 +1019,6 @@ static int its_alloc_device_irq(struct its_device *dev, u32 id,
         return -ENOSPC;
 
     *hwirq = dev->lpi_base + idx;
-    *irq = irq_create_mapping(lpi_domain, *hwirq);
-    if (!*irq)
-        return -ENOSPC;    /* Don't kill the device, though */
 
     set_bit(idx, dev->lpi_map);
 
@@ -1113,134 +1028,52 @@ static int its_alloc_device_irq(struct its_device *dev, u32 id,
     return 0;
 }
 
-
-
-static int its_msi_get_vec_count(struct pci_dev *pdev, struct msi_desc *desc)
-{
-#ifdef CONFIG_PCI_MSI
-    if (desc->msi_attrib.is_msix)
-        return pci_msix_vec_count(pdev);
-    else
-        return pci_msi_vec_count(pdev);
-#else
-    return -EINVAL;
-#endif
-}
-
-int pci_requester_id(struct pci_dev *dev);
-static int its_msi_setup_irq(struct msi_chip *chip,
-                             struct pci_dev *pdev,
-                             struct msi_desc *desc)
-{
-    struct its_node *its = container_of(chip, struct its_node, msi_chip);
-    struct its_device *its_dev;
-    struct msi_msg msg;
-    unsigned int irq;
-    u64 addr;
-    int hwirq;
-    int err;
-    u32 dev_id = pci_requester_id(pdev);
-    u32 vec_nr;
-
-    its_dev = its_find_device(its, dev_id);
-    if (!its_dev) {
-        int nvec = its_msi_get_vec_count(pdev, desc);
-        if (WARN_ON(nvec <= 0))
-            return nvec;
-        its_dev = its_create_device(its, dev_id, nvec);
-    }
-    if (!its_dev)
-        return -ENOMEM;
-    vec_nr = its_msi_get_entry_nr(desc);
-    err = its_alloc_device_irq(its_dev, vec_nr, &hwirq, &irq);
-    if (err)
-        return err;
-
-    irq_set_msi_desc(irq, desc);
-    irq_set_handler_data(irq, its_dev);
-
-    addr = its->phys_base + GITS_TRANSLATER;
-
-    msg.address_lo        = (u32)addr;
-    msg.address_hi        = (u32)(addr >> 32);
-    msg.data        = vec_nr;
-
-    write_msi_msg(irq, &msg);
-    return 0;
-}
-
-static void its_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
-{
-    struct irq_data *d = irq_get_irq_data(irq);
-    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
-
-    BUG_ON(d->hwirq < its_dev->lpi_base ||        /* OMG! */
-           d->hwirq > (its_dev->lpi_base + its_dev->nr_lpis));
-
-    /* Stop the delivery of interrupts */
-    its_send_discard(its_dev, its_msi_get_entry_nr(d->msi_desc));
-
-    /* Mark interrupt index as unused, and clear the mapping */
-    clear_bit(d->hwirq - its_dev->lpi_base, its_dev->lpi_map);
-    irq_dispose_mapping(irq);
-
-    /* If all interrupts have been freed, start mopping the floor */
-    if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
-        its_lpi_free(its_dev->lpi_map,
-                     its_dev->lpi_base,
-                     its_dev->nr_lpis);
-
-        /* Unmap device/itt */
-        its_send_mapd(its_dev, 0);
-        its_free_device(its_dev);
-    }
-}
-
-static int its_probe(struct device_node *node)
+static int its_probe(struct dt_device_node *node)
 {
-    struct resource res;
+    paddr_t its_addr, its_size;
     struct its_node *its;
     void __iomem *its_base;
     u32 val;
     u64 baser, tmp;
     int err;
 
-    err = of_address_to_resource(node, 0, &res);
-    if (err) {
-        pr_warn("%s: no regs?\n", node->full_name);
+    err = dt_device_get_address(node, 0, &its_addr, &its_size);
+    if ( err || !its_addr )
+    {
+        its_warn("%s: cannot find GIC-ITS\n", node->full_name);
         return -ENXIO;
     }
 
-    its_base = ioremap(res.start, resource_size(&res));
-    if (!its_base) {
-        pr_warn("%s: unable to map registers\n", node->full_name);
+    its_base = ioremap_nocache(its_addr, its_size);
+    if ( !its_base)
+    {
+        its_warn("%s: unable to map registers\n", node->full_name);
         return -ENOMEM;
     }
 
-    val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
+    val = readl_relaxed(its_base + GITS_PIDR2) & GICR_PIDR2_ARCH_REV_MASK;
     if (val != 0x30 && val != 0x40) {
-        pr_warn("%s: no ITS detected, giving up\n", node->full_name);
+        its_warn("%s: no ITS detected, giving up\n", node->full_name);
         err = -ENODEV;
         goto out_unmap;
     }
 
-    pr_info("ITS: %s\n", node->full_name);
+    its_info("ITS: %s\n", node->full_name);
 
-    its = kzalloc(sizeof(*its), GFP_KERNEL);
+    its = xzalloc(struct its_node);
     if (!its) {
         err = -ENOMEM;
         goto out_unmap;
     }
 
-    raw_spin_lock_init(&its->lock);
+    spin_lock_init(&its->lock);
     INIT_LIST_HEAD(&its->entry);
     INIT_LIST_HEAD(&its->its_device_list);
     its->base = its_base;
-    its->phys_base = res.start;
-    its->msi_chip.of_node = node;
+    its->phys_base = its_addr;
     its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
 
-    its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
+    its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
     if (!its->cmd_base) {
         err = -ENOMEM;
         goto out_free_its;
@@ -1255,19 +1088,19 @@ static int its_probe(struct device_node *node)
     if (err)
         goto out_free_tables;
 
-    baser = (virt_to_phys(its->cmd_base)    |
-             GITS_CBASER_WaWb               |
-             GITS_CBASER_InnerShareable     |
-             (ITS_CMD_QUEUE_SZ / SZ_4K - 1) |
-             GITS_CBASER_VALID);
+    baser = (__pa(its->cmd_base)            |
+            GITS_CBASER_WaWb                |
+            GITS_CBASER_InnerShareable      |
+            (ITS_CMD_QUEUE_SZ / SZ_4K - 1)  |
+            GITS_CBASER_VALID);
 
     writeq_relaxed(baser, its->base + GITS_CBASER);
     tmp = readq_relaxed(its->base + GITS_CBASER);
-/*    writeq_relaxed(0, its->base + GITS_CWRITER); */
+    writeq_relaxed(0, its->base + GITS_CWRITER);
     writel_relaxed(1, its->base + GITS_CTLR);
 
     if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) {
-        pr_info("ITS: using cache flushing for cmd queue\n");
+        its_info("ITS: using cache flushing for cmd queue\n");
         its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
     }
 
@@ -1275,25 +1108,17 @@ static int its_probe(struct device_node *node)
     list_add(&its->entry, &its_nodes);
     spin_unlock(&its_lock);
 
-    if (IS_ENABLED(CONFIG_PCI_MSI) && /* Remove this once we have PCI... */
-        of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
-        its->msi_chip.setup_irq        = its_msi_setup_irq;
-        its->msi_chip.teardown_irq    = its_msi_teardown_irq;
-
-        err = of_pci_msi_chip_add(&its->msi_chip);
-    }
-
     return err;
 
 out_free_tables:
     its_free_tables(its);
 out_free_cmd:
-    kfree(its->cmd_base);
+    xfree(its->cmd_base);
 out_free_its:
-    kfree(its);
+    xfree(its);
 out_unmap:
-    iounmap(its_base);
-    pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
+    //TODO: no call for iounmap in xen?
+    its_err("ITS: failed probing %s (%d)\n", node->full_name, err);
     return err;
 }
 
@@ -1305,7 +1130,7 @@ static bool gic_rdists_supports_plpis(void)
 int its_cpu_init(void)
 {
     if (!gic_rdists_supports_plpis()) {
-        pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
+        its_info("CPU%d: LPIs not supported\n", smp_processor_id());
         return -ENXIO;
     }
 
@@ -1317,32 +1142,45 @@ int its_cpu_init(void)
     return 0;
 }
 
-static struct of_device_id its_device_id[] = {
-    {    .compatible    = "arm,gic-v3-its",    },
-    {},
-};
-
-struct irq_chip *its_init(struct device_node *node, struct rdists *rdists,
-                          struct irq_domain *domain)
+int its_init(struct dt_device_node *node, struct rdist_prop *rdists)
 {
-    struct device_node *np;
+    static const struct dt_device_match its_device_ids[] __initconst =
+    {
+        DT_MATCH_COMPATIBLE("arm,gic-v3-its"),
+        { /* sentinel */ },
+    };
+    struct dt_device_node *np = NULL;
 
-    for (np = of_find_matching_node(node, its_device_id); np;
-         np = of_find_matching_node(np, its_device_id)) {
-        its_probe(np);
+    while ( (np = dt_find_matching_node(np, its_device_ids)) )
+    {
+        if ( !dt_find_property(np, "msi-controller", NULL) )
+            continue;
+
+        if ( dt_get_parent(np) )
+            break;
     }
+    if ( np )
+        its_probe(np);
 
     if (list_empty(&its_nodes)) {
-        pr_info("ITS: No ITS available, not enabling LPIs\n");
-        return NULL;
+        its_info("ITS: No ITS available, not enabling LPIs\n");
+        return -ENXIO;
     }
 
     gic_rdists = rdists;
     gic_root_node = node;
-    lpi_domain = domain;
 
     its_alloc_lpi_tables();
     its_lpi_init(rdists->id_bits);
 
-    return &its_irq_chip;
+    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/gic-v3.c b/xen/arch/arm/gic-v3.c
index 47452ca..5c35ac5 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -63,6 +63,7 @@ static struct gic_info gicv3_info;
 
 /* per-cpu re-distributor base */
 static DEFINE_PER_CPU(void __iomem*, rbase);
+DEFINE_PER_CPU(struct rdist, rdist);
 
 #define GICD                   (gicv3.map_dbase)
 #define GICD_RDIST_BASE        (this_cpu(rbase))
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 13adb53..83d75cf 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -110,6 +110,23 @@
 #define GICR_ICFGR1                  (0x0C04)
 #define GICR_NSACR                   (0x0E00)
 
+#define GICR_CTLR_ENABLE_LPIS        (1UL << 0)
+#define GICR_TYPER_CPU_NUMBER(r)	(((r) >> 8) & 0xffff)
+
+#define GICR_PROPBASER_NonShareable	(0U << 10)
+#define GICR_PROPBASER_InnerShareable	(1U << 10)
+#define GICR_PROPBASER_OuterShareable	(2U << 10)
+#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PROPBASER_nCnB		(0U << 7)
+#define GICR_PROPBASER_nC		(1U << 7)
+#define GICR_PROPBASER_RaWt		(2U << 7)
+#define GICR_PROPBASER_RaWb		(3U << 7)
+#define GICR_PROPBASER_WaWt		(4U << 7)
+#define GICR_PROPBASER_WaWb		(5U << 7)
+#define GICR_PROPBASER_RaWaWt		(6U << 7)
+#define GICR_PROPBASER_RaWaWb		(7U << 7)
+#define GICR_PROPBASER_IDBITS_MASK	(0x1f)
+
 #define GICR_TYPER_PLPIS             (1U << 0)
 #define GICR_TYPER_VLPIS             (1U << 1)
 #define GICR_TYPER_LAST              (1U << 4)
@@ -149,6 +166,116 @@
 #define ICH_SGI_IRQ_SHIFT            24
 #define ICH_SGI_IRQ_MASK             0xf
 #define ICH_SGI_TARGETLIST_MASK      0xffff
+
+#define GICR_TYPER_PLPIS                (1U << 0)
+#define GICR_TYPER_VLPIS                (1U << 1)
+#define GICR_TYPER_LAST                 (1U << 4)
+ 
+#define LPI_PROP_GROUP1                 (1 << 1)
+#define LPI_PROP_ENABLED                (1 << 0)
+
+/*
+ * ITS registers, offsets from ITS_base
+ */
+#define GITS_CTLR                       0x0000
+#define GITS_IIDR                       0x0004
+#define GITS_TYPER                      0x0008
+#define GITS_CBASER                     0x0080
+#define GITS_CWRITER                    0x0088
+#define GITS_CREADR                     0x0090
+#define GITS_BASER                      0x0100
+#define GITS_BASERN                     0x013c
+#define GITS_PIDR0                      GICR_PIDR0
+#define GITS_PIDR1                      GICR_PIDR1
+#define GITS_PIDR2                      GICR_PIDR2
+#define GITS_PIDR3                      GICR_PIDR3
+#define GITS_PIDR4                      GICR_PIDR4
+#define GITS_PIDR5                      GICR_PIDR5
+#define GITS_PIDR7                      GICR_PIDR7
+
+#define GITS_TRANSLATER                 0x10040
+
+#define GITS_TYPER_PTA                  (1UL << 19)
+
+#define GITS_CBASER_VALID               (1UL << 63)
+#define GITS_CBASER_nCnB                (0UL << 59)
+#define GITS_CBASER_nC                  (1UL << 59)
+#define GITS_CBASER_RaWt                (2UL << 59)
+#define GITS_CBASER_RaWb                (3UL << 59)
+#define GITS_CBASER_WaWt                (4UL << 59)
+#define GITS_CBASER_WaWb                (5UL << 59)
+#define GITS_CBASER_RaWaWt              (6UL << 59)
+#define GITS_CBASER_RaWaWb              (7UL << 59)
+#define GITS_CBASER_NonShareable        (0UL << 10)
+#define GITS_CBASER_InnerShareable      (1UL << 10)
+#define GITS_CBASER_OuterShareable      (2UL << 10)
+#define GITS_CBASER_SHAREABILITY_MASK   (3UL << 10)
+
+#define GITS_BASER_NR_REGS              8
+
+#define GITS_BASER_VALID                (1UL << 63)
+#define GITS_BASER_nCnB                 (0UL << 59)
+#define GITS_BASER_nC                   (1UL << 59)
+#define GITS_BASER_RaWt                 (2UL << 59)
+#define GITS_BASER_RaWb                 (3UL << 59)
+#define GITS_BASER_WaWt                 (4UL << 59)
+#define GITS_BASER_WaWb                 (5UL << 59)
+#define GITS_BASER_RaWaWt               (6UL << 59)
+#define GITS_BASER_RaWaWb               (7UL << 59)
+#define GITS_BASER_TYPE_SHIFT		(56)
+#define GITS_BASER_TYPE(r)		(((r) >> GITS_BASER_TYPE_SHIFT) & 7)
+#define GITS_BASER_ENTRY_SIZE_SHIFT	(48)
+#define GITS_BASER_ENTRY_SIZE(r)	((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1)
+#define GITS_BASER_NonShareable		(0UL << 10)
+#define GITS_BASER_InnerShareable	(1UL << 10)
+#define GITS_BASER_OuterShareable	(2UL << 10)
+#define GITS_BASER_SHAREABILITY_SHIFT	(10)
+#define GITS_BASER_SHAREABILITY_MASK	(3UL << GITS_BASER_SHAREABILITY_SHIFT)
+#define GITS_BASER_PAGE_SIZE_SHIFT	(8)
+#define GITS_BASER_PAGE_SIZE_4K		(0UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_PAGE_SIZE_16K	(1UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_PAGE_SIZE_64K	(2UL << GITS_BASER_PAGE_SIZE_SHIFT)
+#define GITS_BASER_PAGE_SIZE_MASK	(3UL << GITS_BASER_PAGE_SIZE_SHIFT)
+
+#define GITS_BASER_TYPE_NONE		0
+#define GITS_BASER_TYPE_DEVICE		1
+#define GITS_BASER_TYPE_VCPU		2
+#define GITS_BASER_TYPE_CPU		3
+#define GITS_BASER_TYPE_COLLECTION	4
+#define GITS_BASER_TYPE_RESERVED5	5
+#define GITS_BASER_TYPE_RESERVED6	6
+#define GITS_BASER_TYPE_RESERVED7	7
+
+/*
+ * ITS commands
+ */
+#define GITS_CMD_MAPD                   0x08
+#define GITS_CMD_MAPC                   0x09
+#define GITS_CMD_MAPVI                  0x0a
+#define GITS_CMD_MAPI                   0x0b
+#define GITS_CMD_MOVI                   0x01
+#define GITS_CMD_DISCARD                0x0f
+#define GITS_CMD_INV                    0x0c
+#define GITS_CMD_MOVALL                 0x0e
+#define GITS_CMD_INVALL                 0x0d
+#define GITS_CMD_INT                    0x03
+#define GITS_CMD_CLEAR                  0x04
+#define GITS_CMD_SYNC                   0x05
+
+struct rdist {
+    void __iomem *rbase;
+    void * pend_page;
+    paddr_t phys_base;
+};
+
+struct rdist_prop {
+    void * prop_page;
+    int    id_bits;
+    uint64_t flags;
+};
+
+DECLARE_PER_CPU(struct rdist, rdist);
+
 #endif /* __ASM_ARM_GIC_V3_DEFS_H__ */
 
 /*
-- 
1.7.9.5

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

* [RFC PATCH 04/19] xen/arm: its: Move ITS command encode helper functions
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (2 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 05/19] xen/arm: its: Remove unused code in ITS driver vijay.kilari
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

ITS command encode functions are moved to
header file gits-its.h and made as inline functions.
This will be useful later in virtual its driver

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c     |   71 +---------------------------
 xen/include/asm-arm/gic-its.h |  104 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 70 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index cde0ec0..53850fe 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -39,6 +39,7 @@
 #include <asm/device.h>
 #include <asm/gic.h>
 #include <asm/gic_v3_defs.h>
+#include <asm/gic-its.h>
 
 #define its_print(lvl, fmt, ...)                                        \
     printk(lvl "GIC-ITS:" fmt, ## __VA_ARGS__)
@@ -162,82 +163,12 @@ struct its_cmd_desc {
     };
 };
 
-/*
- * The ITS command block, which is what the ITS actually parses.
- */
-struct its_cmd_block {
-    u64 raw_cmd[4];
-};
-
 #define ITS_CMD_QUEUE_SZ            SZ_64K
 #define ITS_CMD_QUEUE_NR_ENTRIES    (ITS_CMD_QUEUE_SZ / sizeof(struct its_cmd_block))
 
 typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
                                 struct its_cmd_desc *);
 
-static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
-{
-    cmd->raw_cmd[0] &= ~0xffULL;
-    cmd->raw_cmd[0] |= cmd_nr;
-}
-
-static void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
-{
-    cmd->raw_cmd[0] &= 0xffffffffULL;
-    cmd->raw_cmd[0] |= ((u64)devid) << 32;
-}
-
-static void its_encode_event_id(struct its_cmd_block *cmd, u32 id)
-{
-    cmd->raw_cmd[1] &= ~0xffffffffULL;
-    cmd->raw_cmd[1] |= id;
-}
-
-static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id)
-{
-    cmd->raw_cmd[1] &= 0xffffffffULL;
-    cmd->raw_cmd[1] |= ((u64)phys_id) << 32;
-}
-
-static void its_encode_size(struct its_cmd_block *cmd, u8 size)
-{
-    cmd->raw_cmd[1] &= ~0xffULL;
-    cmd->raw_cmd[1] |= size;
-}
-
-static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr)
-{
-    cmd->raw_cmd[2] &= ~0xffffffffffffULL;
-    cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00ULL;
-}
-
-static void its_encode_valid(struct its_cmd_block *cmd, int valid)
-{
-    cmd->raw_cmd[2] &= ~(1ULL << 63);
-    cmd->raw_cmd[2] |= ((u64)!!valid) << 63;
-}
-
-static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr)
-{
-    cmd->raw_cmd[2] &= ~(0xffffffffULL << 16);
-    cmd->raw_cmd[2] |= (target_addr & (0xffffffffULL << 16));
-}
-
-static void its_encode_collection(struct its_cmd_block *cmd, u16 col)
-{
-    cmd->raw_cmd[2] &= ~0xffffULL;
-    cmd->raw_cmd[2] |= col;
-}
-
-static inline void its_fixup_cmd(struct its_cmd_block *cmd)
-{
-    /* Let's fixup BE commands */
-    cmd->raw_cmd[0] = cpu_to_le64(cmd->raw_cmd[0]);
-    cmd->raw_cmd[1] = cpu_to_le64(cmd->raw_cmd[1]);
-    cmd->raw_cmd[2] = cpu_to_le64(cmd->raw_cmd[2]);
-    cmd->raw_cmd[3] = cpu_to_le64(cmd->raw_cmd[3]);
-}
-
 static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
new file mode 100644
index 0000000..099ed9c
--- /dev/null
+++ b/xen/include/asm-arm/gic-its.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Xen changes:
+ * Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
+ * Copyright (C) 2014, 2015 Cavium Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_ARM_GIC_ITS_H__
+#define __ASM_ARM_GIC_ITS_H__
+
+/*
+ * The ITS command block, which is what the ITS actually parses.
+ */
+struct its_cmd_block {
+    u64 raw_cmd[4];
+};
+
+static inline void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
+{
+    cmd->raw_cmd[0] &= ~0xffULL;
+    cmd->raw_cmd[0] |= cmd_nr;
+}
+
+static inline void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
+{
+    cmd->raw_cmd[0] &= 0xffffffffULL;
+    cmd->raw_cmd[0] |= ((u64)devid) << 32;
+}
+
+static inline void its_encode_event_id(struct its_cmd_block *cmd, u32 id)
+{
+    cmd->raw_cmd[1] &= ~0xffffffffULL;
+    cmd->raw_cmd[1] |= id;
+}
+
+static inline void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id)
+{
+    cmd->raw_cmd[1] &= 0xffffffffULL;
+    cmd->raw_cmd[1] |= ((u64)phys_id) << 32;
+}
+
+static inline void its_encode_size(struct its_cmd_block *cmd, u8 size)
+{
+    cmd->raw_cmd[1] &= ~0xffULL;
+    cmd->raw_cmd[1] |= size;
+}
+
+static inline void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr)
+{
+    cmd->raw_cmd[2] &= ~0xffffffffffffULL;
+    cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00ULL;
+}
+
+static inline void its_encode_valid(struct its_cmd_block *cmd, int valid)
+{
+    cmd->raw_cmd[2] &= ~(1ULL << 63);
+    cmd->raw_cmd[2] |= ((u64)!!valid) << 63;
+}
+
+static inline void its_encode_target(struct its_cmd_block *cmd, u64 target_addr)
+{
+    cmd->raw_cmd[2] &= ~(0xffffffffULL << 16);
+    cmd->raw_cmd[2] |= (target_addr & (0xffffffffULL << 16));
+}
+
+static inline void its_encode_collection(struct its_cmd_block *cmd, u16 col)
+{
+    cmd->raw_cmd[2] &= ~0xffffULL;
+    cmd->raw_cmd[2] |= col;
+}
+
+static inline void its_fixup_cmd(struct its_cmd_block *cmd)
+{
+    /* Let's fixup BE commands */
+    cmd->raw_cmd[0] = cpu_to_le64(cmd->raw_cmd[0]);
+    cmd->raw_cmd[1] = cpu_to_le64(cmd->raw_cmd[1]);
+    cmd->raw_cmd[2] = cpu_to_le64(cmd->raw_cmd[2]);
+    cmd->raw_cmd[3] = cpu_to_le64(cmd->raw_cmd[3]);
+}
+
+#endif /* __ASM_ARM_GIC_ITS_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] 59+ messages in thread

* [RFC PATCH 05/19] xen/arm: its: Remove unused code in ITS driver
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (3 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 04/19] xen/arm: its: Move ITS command encode helper functions vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 06/19] xen/arm: its: Add helper functions to decode ITS Command vijay.kilari
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

ITS driver does not require functionality to
create/free device. This will be handled by virtual
ITS driver.

The functionality of ITS driver will be limited to
initialization, sending ITS commands received from
Virtual ITS driver and ITS interrupt handling.

The following functionality is removed
 - Remove its_device structure usage
 - Removed used command structure definitions
 - Removed handling of unused ITS commands like MAPD, MAPVI, INT and
   DISCARD and INV

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c |  254 ++-------------------------------------------
 1 file changed, 8 insertions(+), 246 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 53850fe..2ec7866 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -83,29 +83,12 @@ struct its_node {
     struct its_cmd_block  *cmd_write;
     void                  *tables[GITS_BASER_NR_REGS];
     struct its_collection *collections;
-    struct list_head      its_device_list;
     u64                   flags;
     u32                   ite_size;
 };
 
 #define ITS_ITT_ALIGN        SZ_256
 
-/*
- * The ITS view of a device - belongs to an ITS, a collection, owns an
- * interrupt translation table, and a list of interrupts.
- */
-struct its_device {
-    struct list_head       entry;
-    struct its_node        *its;
-    struct its_collection  *collection;
-    void                   *itt;
-    unsigned long          *lpi_map;
-    int                    lpi_base;
-    int                    nr_lpis;
-    u32                    nr_ites;
-    u32                    device_id;
-};
-
 static LIST_HEAD(its_nodes);
 static DEFINE_SPINLOCK(its_lock);
 static struct dt_device_node *gic_root_node;
@@ -121,43 +104,17 @@ static struct rdist_prop  *gic_rdists;
 struct its_cmd_desc {
     union {
         struct {
-            struct its_device *dev;
-            u32 event_id;
-        } its_inv_cmd;
-
-        struct {
-            struct its_device *dev;
-            u32 event_id;
-        } its_int_cmd;
-
-        struct {
-            struct its_device *dev;
-            int valid;
-        } its_mapd_cmd;
-
-        struct {
             struct its_collection *col;
             int valid;
         } its_mapc_cmd;
 
         struct {
-            struct its_device *dev;
-            u32 phys_id;
-            u32 event_id;
-        } its_mapvi_cmd;
-
-        struct {
-            struct its_device *dev;
             struct its_collection *col;
             u32 id;
+            u32 dev_id;
         } its_movi_cmd;
 
         struct {
-            struct its_device *dev;
-            u32 event_id;
-        } its_discard_cmd;
-
-        struct {
             struct its_collection *col;
         } its_invall_cmd;
     };
@@ -169,26 +126,6 @@ struct its_cmd_desc {
 typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
                                 struct its_cmd_desc *);
 
-static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
-                                                 struct its_cmd_desc *desc)
-{
-    unsigned long itt_addr;
-    u8 size = max(fls(desc->its_mapd_cmd.dev->nr_ites) - 1, 1);
-
-    itt_addr = __pa(desc->its_mapd_cmd.dev->itt);
-    itt_addr = ((itt_addr) + (ITS_ITT_ALIGN - 1)) & ~(ITS_ITT_ALIGN - 1);
-
-    its_encode_cmd(cmd, GITS_CMD_MAPD);
-    its_encode_devid(cmd, desc->its_mapd_cmd.dev->device_id);
-    its_encode_size(cmd, size - 1);
-    its_encode_itt(cmd, itt_addr);
-    its_encode_valid(cmd, desc->its_mapd_cmd.valid);
-
-    its_fixup_cmd(cmd);
-
-    return desc->its_mapd_cmd.dev->collection;
-}
-
 static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
@@ -202,55 +139,17 @@ static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
     return desc->its_mapc_cmd.col;
 }
 
-static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd,
-                                                  struct its_cmd_desc *desc)
-{
-    its_encode_cmd(cmd, GITS_CMD_MAPVI);
-    its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id);
-    its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id);
-    its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id);
-    its_encode_collection(cmd, desc->its_mapvi_cmd.dev->collection->col_id);
-
-    its_fixup_cmd(cmd);
-
-    return desc->its_mapvi_cmd.dev->collection;
-}
-
 static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
     its_encode_cmd(cmd, GITS_CMD_MOVI);
-    its_encode_devid(cmd, desc->its_movi_cmd.dev->device_id);
+    its_encode_devid(cmd, desc->its_movi_cmd.dev_id);
     its_encode_event_id(cmd, desc->its_movi_cmd.id);
     its_encode_collection(cmd, desc->its_movi_cmd.col->col_id);
 
     its_fixup_cmd(cmd);
 
-    return desc->its_movi_cmd.dev->collection;
-}
-
-static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
-                                                    struct its_cmd_desc *desc)
-{
-    its_encode_cmd(cmd, GITS_CMD_DISCARD);
-    its_encode_devid(cmd, desc->its_discard_cmd.dev->device_id);
-    its_encode_event_id(cmd, desc->its_discard_cmd.event_id);
-
-    its_fixup_cmd(cmd);
-
-    return desc->its_discard_cmd.dev->collection;
-}
-
-static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
-                                                struct its_cmd_desc *desc)
-{
-    its_encode_cmd(cmd, GITS_CMD_INV);
-    its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id);
-    its_encode_event_id(cmd, desc->its_inv_cmd.event_id);
-
-    its_fixup_cmd(cmd);
-
-    return desc->its_inv_cmd.dev->collection;
+    return desc->its_movi_cmd.col;
 }
 
 static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
@@ -401,26 +300,6 @@ post:
     its_wait_for_range_completion(its, cmd, next_cmd);
 }
 
-void its_send_inv(struct its_device *dev, u32 event_id)
-{
-    struct its_cmd_desc desc;
-
-    desc.its_inv_cmd.dev = dev;
-    desc.its_inv_cmd.event_id = event_id;
-
-    its_send_single_command(dev->its, its_build_inv_cmd, &desc);
-}
-
-static void its_send_mapd(struct its_device *dev, int valid)
-{
-    struct its_cmd_desc desc;
-
-    desc.its_mapd_cmd.dev = dev;
-    desc.its_mapd_cmd.valid = !!valid;
-
-    its_send_single_command(dev->its, its_build_mapd_cmd, &desc);
-}
-
 static void its_send_mapc(struct its_node *its, struct its_collection *col,
               int valid)
 {
@@ -432,37 +311,16 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col,
     its_send_single_command(its, its_build_mapc_cmd, &desc);
 }
 
-static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id)
+void its_send_movi(struct its_node *its, struct its_collection *col,
+                   u32 dev_id, u32 id)
 {
     struct its_cmd_desc desc;
 
-    desc.its_mapvi_cmd.dev = dev;
-    desc.its_mapvi_cmd.phys_id = irq_id;
-    desc.its_mapvi_cmd.event_id = id;
-
-    its_send_single_command(dev->its, its_build_mapvi_cmd, &desc);
-}
-
-void its_send_movi(struct its_device *dev,
-              struct its_collection *col, u32 id)
-{
-    struct its_cmd_desc desc;
-
-    desc.its_movi_cmd.dev = dev;
+    desc.its_movi_cmd.dev_id = dev_id;
     desc.its_movi_cmd.col = col;
     desc.its_movi_cmd.id = id;
 
-    its_send_single_command(dev->its, its_build_movi_cmd, &desc);
-}
-
-void its_send_discard(struct its_device *dev, u32 id)
-{
-    struct its_cmd_desc desc;
-
-    desc.its_discard_cmd.dev = dev;
-    desc.its_discard_cmd.event_id = id;
-
-    its_send_single_command(dev->its, its_build_discard_cmd, &desc);
+    its_send_single_command(its, its_build_movi_cmd, &desc);
 }
 
 static void its_send_invall(struct its_node *its, struct its_collection *col)
@@ -515,7 +373,7 @@ static int its_lpi_init(u32 id_bits)
     return 0;
 }
 
-static unsigned long *its_lpi_alloc_chunks(int nr_irq, int *base, int *nr_ids)
+unsigned long *its_lpi_alloc_chunks(int nr_irq, int *base, int *nr_ids)
 {
     unsigned long *bitmap = NULL;
     int chunk_id;
@@ -864,101 +722,6 @@ static void its_cpu_init_collection(void)
     spin_unlock(&its_lock);
 }
 
-struct its_device *its_find_device(struct its_node *its, u32 dev_id)
-{
-    struct its_device *its_dev = NULL, *tmp;
-
-    spin_lock(&its->lock);
-
-    list_for_each_entry(tmp, &its->its_device_list, entry) {
-        if (tmp->device_id == dev_id) {
-            its_dev = tmp;
-            break;
-        }
-    }
-
-    spin_unlock(&its->lock);
-
-    return its_dev;
-}
-
-/* TODO: Removed static for compilation */
-struct its_device *its_create_device(struct its_node *its, u32 dev_id,
-                                     int nvecs)
-{
-    struct its_device *dev;
-    unsigned long *lpi_map;
-    void *itt;
-    int lpi_base;
-    int nr_lpis;
-    int cpu;
-    int sz;
-
-    dev = xzalloc(struct its_device);
-    sz = nvecs * its->ite_size;
-    sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
-    itt = xzalloc_bytes(sz);
-    lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
-
-    if (!dev || !itt || !lpi_map) {
-        xfree(dev);
-        xfree(itt);
-        xfree(lpi_map);
-        return NULL;
-    }
-
-    dev->its = its;
-    dev->itt = itt;
-    dev->nr_ites = nvecs;
-    dev->lpi_map = lpi_map;
-    dev->lpi_base = lpi_base;
-    dev->nr_lpis = nr_lpis;
-    dev->device_id = dev_id;
-    INIT_LIST_HEAD(&dev->entry);
-
-    spin_lock(&its->lock);
-    list_add(&dev->entry, &its->its_device_list);
-    spin_unlock(&its->lock);
-
-    /* Bind the device to the first possible CPU */
-    cpu = cpumask_first(&cpu_online_map);
-    dev->collection = &its->collections[cpu];
-
-    /* Map device to its ITT */
-    its_send_mapd(dev, 1);
-
-    return dev;
-}
-
-void its_free_device(struct its_device *its_dev)
-{
-    spin_lock(&its_dev->its->lock);
-    list_del(&its_dev->entry);
-    spin_unlock(&its_dev->its->lock);
-    xfree(its_dev->itt);
-    xfree(its_dev);
-}
-
-/* TODO: Removed static for compilation */
-int its_alloc_device_irq(struct its_device *dev, u32 id,
-                         int *hwirq, unsigned int *irq)
-{
-    int idx;
-
-    idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis);
-    if (idx == dev->nr_lpis)
-        return -ENOSPC;
-
-    *hwirq = dev->lpi_base + idx;
-
-    set_bit(idx, dev->lpi_map);
-
-    /* Map the GIC irq ID to the device */
-    its_send_mapvi(dev, *hwirq, id);
-
-    return 0;
-}
-
 static int its_probe(struct dt_device_node *node)
 {
     paddr_t its_addr, its_size;
@@ -999,7 +762,6 @@ static int its_probe(struct dt_device_node *node)
 
     spin_lock_init(&its->lock);
     INIT_LIST_HEAD(&its->entry);
-    INIT_LIST_HEAD(&its->its_device_list);
     its->base = its_base;
     its->phys_base = its_addr;
     its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
-- 
1.7.9.5

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

* [RFC PATCH 06/19] xen/arm: its: Add helper functions to decode ITS Command
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (4 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 05/19] xen/arm: its: Remove unused code in ITS driver vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 07/19] xen/arm: vits: Move LPI handling to basic virtual its driver vijay.kilari
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Add helper functions to decode ITS command
This will be useful for Virtual ITS driver

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/include/asm-arm/gic-its.h |   45 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 099ed9c..ff13c91 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -29,6 +29,51 @@ struct its_cmd_block {
     u64 raw_cmd[4];
 };
 
+static inline uint8_t its_decode_cmd(struct its_cmd_block *cmd)
+{
+    return cmd->raw_cmd[0] & 0xff;
+}
+
+static inline uint32_t its_decode_devid(struct domain *d, struct its_cmd_block *cmd)
+{
+    return (cmd->raw_cmd[0] >> 32);
+}
+
+static inline uint32_t its_decode_event_id(struct its_cmd_block *cmd)
+{
+    return (uint32_t)cmd->raw_cmd[1];
+}
+
+static inline uint32_t its_decode_phys_id(struct its_cmd_block *cmd)
+{
+    return cmd->raw_cmd[1] >> 32;
+}
+
+static inline uint8_t its_decode_size(struct its_cmd_block *cmd)
+{
+    return (u8)(cmd->raw_cmd[1] & 0xff);
+}
+
+static inline uint64_t its_decode_itt(struct its_cmd_block *cmd)
+{
+    return (cmd->raw_cmd[2] & 0xffffffffff00ULL);
+}
+
+static inline int its_decode_valid(struct its_cmd_block *cmd)
+{
+    return cmd->raw_cmd[2] >> 63;
+}
+
+static inline uint64_t its_decode_target(struct its_cmd_block *cmd)
+{
+    return (cmd->raw_cmd[2] & 0xffffffff0000ULL);
+}
+
+static inline u16 its_decode_collection(struct its_cmd_block *cmd)
+{
+    return (u16)(cmd->raw_cmd[2] & 0xffffULL);
+}
+
 static inline void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr)
 {
     cmd->raw_cmd[0] &= ~0xffULL;
-- 
1.7.9.5

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

* [RFC PATCH 07/19] xen/arm: vits: Move LPI handling to basic virtual its driver
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (5 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 06/19] xen/arm: its: Add helper functions to decode ITS Command vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 08/19] xen/arm: Add helper function to get domain page vijay.kilari
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

The LPI allocation is handled by virtual ITS driver on
receiving ITS commands from domain. So move this functionality
from physical ITS driver to Virtual ITS driver.

This patch does not add any virtual its funtionality
except moving required code for handling LPIs

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/Makefile         |    1 +
 xen/arch/arm/gic-v3-its.c     |  101 -------------------------
 xen/arch/arm/vgic-v3-its.c    |  167 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic-its.h |   21 ++++++
 xen/include/asm-arm/gic.h     |    1 +
 5 files changed, 190 insertions(+), 101 deletions(-)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index f6eb834..c47dcc0 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -32,6 +32,7 @@ obj-y += shutdown.o
 obj-y += traps.o
 obj-y += vgic.o vgic-v2.o
 obj-$(CONFIG_ARM_64) += vgic-v3.o
+obj-$(CONFIG_ARM_64) += vgic-v3-its.o
 obj-y += vtimer.o
 obj-y += vuart.o
 obj-y += hvm.o
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 2ec7866..b1c599f 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -333,106 +333,6 @@ static void its_send_invall(struct its_node *its, struct its_collection *col)
 }
 
 /*
- * How we allocate LPIs:
- *
- * The GIC has id_bits bits for interrupt identifiers. From there, we
- * must subtract 8192 which are reserved for SGIs/PPIs/SPIs. Then, as
- * we allocate LPIs by chunks of 32, we can shift the whole thing by 5
- * bits to the right.
- *
- * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
- */
-#define IRQS_PER_CHUNK_SHIFT    5
-#define IRQS_PER_CHUNK        (1 << IRQS_PER_CHUNK_SHIFT)
-
-static unsigned long *lpi_bitmap;
-static u32 lpi_chunks;
-static DEFINE_SPINLOCK(lpi_lock);
-
-static int its_lpi_to_chunk(int lpi)
-{
-    return (lpi - 8192) >> IRQS_PER_CHUNK_SHIFT;
-}
-
-int its_chunk_to_lpi(int chunk)
-{
-    return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
-}
-
-static int its_lpi_init(u32 id_bits)
-{
-    lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
-
-    lpi_bitmap =  xzalloc_bytes(lpi_chunks / 8);
-    if (!lpi_bitmap) {
-        lpi_chunks = 0;
-        return -ENOMEM;
-    }
-
-    its_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
-    return 0;
-}
-
-unsigned long *its_lpi_alloc_chunks(int nr_irq, int *base, int *nr_ids)
-{
-    unsigned long *bitmap = NULL;
-    int chunk_id;
-    int nr_chunks;
-    int i;
-
-    nr_chunks = DIV_ROUND_UP(nr_irq, IRQS_PER_CHUNK);
-
-    spin_lock(&lpi_lock);
-
-    do {
-        chunk_id = find_next_zero_bit(lpi_bitmap, lpi_chunks, 0);
-        if (chunk_id < lpi_chunks)
-            break;
-
-        nr_chunks--;
-    } while (nr_chunks > 0);
-
-    if (!nr_chunks)
-        goto out;
-
-    bitmap = xzalloc_bytes(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long));
-    if (!bitmap)
-        goto out;
-
-    for (i = 0; i < nr_chunks; i++)
-        set_bit(chunk_id + i, lpi_bitmap);
-
-    *base = its_chunk_to_lpi(chunk_id);
-    *nr_ids = nr_chunks * IRQS_PER_CHUNK;
-
-out:
-    spin_unlock(&lpi_lock);
-
-    return bitmap;
-}
-
-void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
-{
-    int lpi;
-
-    spin_lock(&lpi_lock);
-
-    for (lpi = base; lpi < (base + nr_ids); lpi += IRQS_PER_CHUNK) {
-        int chunk = its_lpi_to_chunk(lpi);
-        BUG_ON(chunk > lpi_chunks);
-        if (test_bit(chunk, lpi_bitmap)) {
-            clear_bit(chunk, lpi_bitmap);
-        } else {
-            its_err("Bad LPI chunk %d\n", chunk);
-        }
-    }
-
-    spin_unlock(&lpi_lock);
-
-    xfree(bitmap);
-}
-
-/*
  * We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to
  * deal with (one configuration byte per interrupt). PENDBASE has to
  * be 64kB aligned (one bit per LPI, plus 8192 bits for SPI/PPI/SGI).
@@ -864,7 +764,6 @@ int its_init(struct dt_device_node *node, struct rdist_prop *rdists)
     gic_root_node = node;
 
     its_alloc_lpi_tables();
-    its_lpi_init(rdists->id_bits);
 
     return 0;
 }
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
new file mode 100644
index 0000000..08e9787
--- /dev/null
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Xen changes:
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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/list.h>
+#include <xen/sched.h>
+#include <xen/sizes.h>
+#include <xen/xmalloc.h>
+#include <asm/current.h>
+#include <asm/device.h>
+#include <asm/mmio.h>
+#include <asm/io.h>
+#include <asm/gic_v3_defs.h>
+#include <asm/gic.h>
+#include <asm/vgic.h>
+#include <asm/gic-its.h>
+
+//#define DEBUG_ITS
+
+#ifdef DEBUG_ITS
+# define DPRINTK(fmt, args...) printk(XENLOG_DEBUG fmt, ##args)
+#else
+# define DPRINTK(fmt, args...) do {} while ( 0 )
+#endif
+
+#ifdef DEBUG_ITS
+static void dump_cmd(struct its_cmd_block *cmd)
+{
+    printk("CMD[0] = 0x%lx CMD[1] = 0x%lx CMD[2] = 0x%lx CMD[3] = 0x%lx\n",
+           cmd->raw_cmd[0], cmd->raw_cmd[1], cmd->raw_cmd[2], cmd->raw_cmd[3]);
+}
+#endif
+
+/*
+ * How we allocate LPIs:
+ *
+ * The GIC has id_bits bits for interrupt identifiers. From there, we
+ * must subtract 8192 which are reserved for SGIs/PPIs/SPIs. Then, as
+ * we allocate LPIs by chunks of 32, we can shift the whole thing by 5
+ * bits to the right.
+ *
+ * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
+ */
+
+#define IRQS_PER_CHUNK_SHIFT    5
+#define IRQS_PER_CHUNK          (1 << IRQS_PER_CHUNK_SHIFT)
+
+static unsigned long *lpi_bitmap;
+static uint32_t lpi_chunks;
+static DEFINE_SPINLOCK(lpi_lock);
+
+static int its_lpi_to_chunk(int lpi)
+{
+    return (lpi - NR_GIC_LPI) >> IRQS_PER_CHUNK_SHIFT;
+}
+
+static int its_chunk_to_lpi(int chunk)
+{
+    return (chunk << IRQS_PER_CHUNK_SHIFT) + NR_GIC_LPI;
+}
+
+int its_lpi_init(uint32_t id_bits)
+{
+    spin_lock(&lpi_lock);
+
+    lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
+
+    lpi_bitmap =  xzalloc_bytes(lpi_chunks / 8);
+    if ( !lpi_bitmap )
+    {
+        lpi_chunks = 0;
+        spin_unlock(&lpi_lock);
+        return -ENOMEM;
+    }
+
+    spin_unlock(&lpi_lock);
+    DPRINTK("vITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
+    return 0;
+}
+
+
+struct its_lpi_chunk *its_lpi_alloc(void)
+{
+    struct its_lpi_chunk *chunk;
+    int lpi;
+
+    chunk = xzalloc(struct its_lpi_chunk);
+    if ( !chunk )
+        return NULL;
+
+    spin_lock(&lpi_lock);
+
+    lpi = find_first_zero_bit(lpi_bitmap, lpi_chunks);
+    if ( lpi < lpi_chunks )
+    {
+        set_bit(lpi, lpi_bitmap);
+        chunk->lpi_base = its_chunk_to_lpi(lpi);
+        chunk->lpi_map = 0;
+        INIT_LIST_HEAD(&chunk->entry);
+        DPRINTK("vITS: Allocated LPI %d LPI_BASE %d\n", lpi, chunk->lpi_base);
+    }
+    else
+        lpi = -ENOSPC;
+
+    spin_unlock(&lpi_lock);
+
+    if ( lpi < 0 )
+    {
+        xfree(chunk);
+        return NULL;
+    }
+
+    return chunk;
+}
+
+void its_lpi_free(struct its_lpi_chunk *chunk)
+{
+    int lpi;
+
+    spin_lock(&lpi_lock);
+
+    lpi = its_lpi_to_chunk(chunk->lpi_base);
+    BUG_ON(lpi > lpi_chunks);
+    if ( test_bit(lpi, lpi_bitmap) )
+    {
+        clear_bit(lpi, lpi_bitmap);
+        DPRINTK("vITS: Freeing lpi chunk %d\n", lpi);
+    }
+    else
+        dprintk(XENLOG_ERR, "Bad LPI chunk %d\n", lpi);
+
+    spin_unlock(&lpi_lock);
+
+    xfree(chunk);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index ff13c91..2fca1ef 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -22,6 +22,27 @@
 #ifndef __ASM_ARM_GIC_ITS_H__
 #define __ASM_ARM_GIC_ITS_H__
 
+#define IRQ_PER_CHUNK 32
+
+/*
+ * Our LPI allocation unit - Chunks of 32 IDs
+ */
+struct its_lpi_chunk {
+    struct list_head entry;
+    /* physical lpi starting number of this chunk */
+    int lpi_base;
+    /* bitmap of allocated plpi */
+    unsigned long lpi_map;
+    /* vlpi vs plpi mapping vs virtual collection */
+    uint32_t vid[IRQ_PER_CHUNK];
+    /* Physical id */
+    uint32_t pid[IRQ_PER_CHUNK];
+    /* Virtual collection id on which this virtual lpi is mapped */
+    uint32_t vcol_id[IRQ_PER_CHUNK];
+    /* LPI ID */
+    uint32_t id[IRQ_PER_CHUNK];
+};
+
 /*
  * The ITS command block, which is what the ITS actually parses.
  */
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 187dc46..1b4b7d1 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -20,6 +20,7 @@
 
 #define NR_GIC_LOCAL_IRQS  NR_LOCAL_IRQS
 #define NR_GIC_SGI         16
+#define NR_GIC_LPI         8192
 #define MAX_RDIST_COUNT    4
 
 #define GICD_CTLR       (0x000)
-- 
1.7.9.5

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

* [RFC PATCH 08/19] xen/arm: Add helper function to get domain page
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (6 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 07/19] xen/arm: vits: Move LPI handling to basic virtual its driver vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support vijay.kilari
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Given the physical address of the page, get
the maddr to map in Xen to access domain's memory.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/p2m.c        |   24 ++++++++++++++++++++++++
 xen/include/asm-arm/p2m.h |    3 +++
 2 files changed, 27 insertions(+)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 8809f5a..b19c5e9 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -1152,6 +1152,30 @@ unsigned long gmfn_to_mfn(struct domain *d, unsigned long gpfn)
     return p >> PAGE_SHIFT;
 }
 
+struct page_info *get_page_from_paddr(struct domain *d, paddr_t paddr,
+                                      unsigned long flags)
+{
+    struct p2m_domain *p2m = &d->arch.p2m;
+    struct page_info *page = NULL;
+
+    ASSERT(d == current->domain);
+
+    spin_lock(&p2m->lock);
+
+    if ( !mfn_valid(paddr >> PAGE_SHIFT) )
+        goto err;
+
+    page = mfn_to_page(paddr >> PAGE_SHIFT);
+    ASSERT(page);
+
+    if ( unlikely(!get_page(page, d)) )
+        page = NULL;
+
+err:
+    spin_unlock(&p2m->lock);
+    return page;
+}
+
 struct page_info *get_page_from_gva(struct domain *d, vaddr_t va,
                                     unsigned long flags)
 {
diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
index da36504..7947e1b 100644
--- a/xen/include/asm-arm/p2m.h
+++ b/xen/include/asm-arm/p2m.h
@@ -147,6 +147,9 @@ void guest_physmap_remove_page(struct domain *d,
 
 unsigned long gmfn_to_mfn(struct domain *d, unsigned long gpfn);
 
+struct page_info *get_page_from_paddr(struct domain *d, paddr_t paddr,
+                                      unsigned long flags);
+
 /*
  * Populate-on-demand
  */
-- 
1.7.9.5

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

* [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (7 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 08/19] xen/arm: Add helper function to get domain page vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 14:17   ` Julien Grall
  2015-03-03 17:54   ` Stefano Stabellini
  2015-03-02 12:30 ` [RFC PATCH 10/19] xen/arm: its: Add virtual ITS command support vijay.kilari
                   ` (11 subsequent siblings)
  20 siblings, 2 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Introduce new fields in irq descriptors for
LPI support. data field to hold irq related data
and virq to hold virtual lpi number for the corresponding
irq

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/irq.c        |   18 ++++++++++++++++++
 xen/include/asm-arm/irq.h |    3 ++-
 xen/include/xen/irq.h     |    2 ++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index cb9c99b..d52ee0c 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -89,6 +89,7 @@ static int __cpuinit init_local_irq_data(void)
         init_one_irq_desc(desc);
         desc->irq = irq;
         desc->action  = NULL;
+        desc->data = NULL;
 
         /* PPIs are included in local_irqs, we copy the IRQ type from
          * local_irqs_type when bringing up local IRQ for this CPU in
@@ -104,6 +105,23 @@ static int __cpuinit init_local_irq_data(void)
     return 0;
 }
 
+int irq_set_desc_data(unsigned int irq, void *d)
+{
+    unsigned long flags;
+    struct irq_desc *desc = irq_to_desc(irq);
+
+    spin_lock_irqsave(&desc->lock, flags);
+    desc->data = d;
+    spin_unlock_irqrestore(&desc->lock, flags);
+
+    return 0;
+}
+
+void *irq_get_desc_data(struct irq_desc *d)
+{
+    return d->data;
+}
+
 void __init init_IRQ(void)
 {
     int irq;
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 435dfcd..de029e4 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -46,7 +46,8 @@ void arch_move_irqs(struct vcpu *v);
 
 /* Set IRQ type for an SPI */
 int irq_set_spi_type(unsigned int spi, unsigned int type);
-
+int irq_set_desc_data(unsigned int irq, void *d);
+void *irq_get_desc_data(struct irq_desc *d);
 int platform_get_irq(const struct dt_device_node *device, int index);
 
 void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
index 9e0155c..f12afac 100644
--- a/xen/include/xen/irq.h
+++ b/xen/include/xen/irq.h
@@ -91,6 +91,8 @@ typedef struct irq_desc {
     spinlock_t lock;
     struct arch_irq_desc arch;
     cpumask_var_t affinity;
+    void *data;   /* IRQ specific data */
+    int virq;     /* Used to store vlpi */
 
     /* irq ratelimit */
     s_time_t rl_quantum_start;
-- 
1.7.9.5

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

* [RFC PATCH 10/19] xen/arm: its: Add virtual ITS command support
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (8 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 11/19] xen/arm: its: Add emulation of ITS control registers vijay.kilari
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Add Virtual ITS command processing support to
Virtual ITS driver. Also add API's to in physical
ITS driver to send commands from Virtual ITS driver.

For now, this driver can handle one physical ITS node.
If platform has more than one physical ITS node, it
need changes at the PCI device level to map pci device
to physical ITS node.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c     |  100 ++++-
 xen/arch/arm/vgic-v3-its.c    |  839 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/domain.h  |    2 +
 xen/include/asm-arm/gic-its.h |   76 ++++
 4 files changed, 1016 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index b1c599f..68bb7ba 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -41,6 +41,14 @@
 #include <asm/gic_v3_defs.h>
 #include <asm/gic-its.h>
 
+//#define DEBUG_GIC_ITS
+
+#ifdef DEBUG_GIC_ITS
+# define DPRINTK(fmt, args...) printk(XENLOG_DEBUG fmt, ##args)
+#else
+# define DPRINTK(fmt, args...) do {} while ( 0 )
+#endif
+
 #define its_print(lvl, fmt, ...)                                        \
     printk(lvl "GIC-ITS:" fmt, ## __VA_ARGS__)
 
@@ -59,6 +67,8 @@
 
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
 
+struct its_node *its;
+
 /*
  * Collection structure - just an ID, and a redistributor address to
  * ping. We use one per CPU as a bag of interrupts assigned to this
@@ -67,6 +77,7 @@
 struct its_collection {
     u64 target_address;
     u16 col_id;
+    u16 valid;
 };
 
 /*
@@ -79,12 +90,14 @@ struct its_node {
     struct                list_head entry;
     void __iomem          *base;
     unsigned long         phys_base;
+    unsigned long         phys_size;
     struct its_cmd_block  *cmd_base;
     struct its_cmd_block  *cmd_write;
     void                  *tables[GITS_BASER_NR_REGS];
     struct its_collection *collections;
     u64                   flags;
     u32                   ite_size;
+    u32                   nr_collections;
 };
 
 #define ITS_ITT_ALIGN        SZ_256
@@ -163,6 +176,68 @@ static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
     return NULL;
 }
 
+int its_check_target(uint64_t vta)
+{
+    int i;
+    struct its_collection *col;
+
+    for ( i = 0; i < its->nr_collections; i++ )
+    {
+        col = &its->collections[i];
+        if ( col->valid && col->target_address == vta )
+        {
+             DPRINTK("ITS: Found valid pta entry 0x%lx for vta 0x%lx\n",
+                     col->target_address, vta);
+             return 0;
+        }
+    }
+
+    DPRINTK("ITS: Cannot find valid pta entry for vta 0x%lx\n", vta);
+    return 1;
+}
+
+int its_get_target(uint8_t pcid, uint64_t *pta)
+{
+    int i;
+    struct its_collection *col;
+
+    for ( i = 0; i < its->nr_collections; i++ )
+    {
+        col = &its->collections[i];
+        if ( col->valid && col->col_id == pcid )
+        {
+             *pta = col->target_address;
+             DPRINTK("ITS: Found valid pta entry 0x%lx for vta 0x%lx\n",
+                     col->target_address, vta);
+             return 0;
+        }
+    }
+
+    DPRINTK("ITS: Cannot find valid pta entry for vta 0x%lx\n", vta);
+    return 1;
+}
+
+int its_get_physical_cid(uint32_t *col_id, uint64_t vta)
+{
+    int i;
+    struct its_collection *col;
+
+    for ( i = 0; i < its->nr_collections; i++ )
+    {
+        col = &its->collections[i];
+        if ( col->valid && col->target_address == vta )
+        {
+            *col_id = col->col_id;
+             DPRINTK("ITS: Found pta 0x%lx vta 0x%lx pcol_id %d\n",
+                     col->target_address, vta, col->col_id);
+             return 0;
+        }
+    }
+
+    DPRINTK("ITS: Cannot find pta entry for vta 0x%lx\n", vta);
+    return 1;
+}
+
 static u64 its_cmd_ptr_to_offset(struct its_node *its,
                                  struct its_cmd_block *ptr)
 {
@@ -513,6 +588,29 @@ static int its_alloc_collections(struct its_node *its)
     return 0;
 }
 
+int gic_its_send_cmd(struct vcpu *v, struct its_cmd_block *phys_cmd)
+{
+    struct its_cmd_block *cmd, *next_cmd;
+
+    spin_lock(&its->lock);
+
+    cmd = its_allocate_entry(its);
+    if ( !cmd )
+        return 0;        /* We're soooooo screewed... */
+
+    cmd->raw_cmd[0] = phys_cmd->raw_cmd[0];
+    cmd->raw_cmd[1] = phys_cmd->raw_cmd[1];
+    cmd->raw_cmd[2] = phys_cmd->raw_cmd[2];
+    cmd->raw_cmd[3] = phys_cmd->raw_cmd[3];
+    its_flush_cmd(its, cmd);
+
+    next_cmd = its_post_commands(its);
+    spin_unlock(&its->lock);
+
+    its_wait_for_range_completion(its, cmd, next_cmd);
+    return 1;
+}
+
 static void its_cpu_init_lpis(void)
 {
     void __iomem *rbase = gic_data_rdist_rd_base();
@@ -625,7 +723,6 @@ static void its_cpu_init_collection(void)
 static int its_probe(struct dt_device_node *node)
 {
     paddr_t its_addr, its_size;
-    struct its_node *its;
     void __iomem *its_base;
     u32 val;
     u64 baser, tmp;
@@ -664,6 +761,7 @@ static int its_probe(struct dt_device_node *node)
     INIT_LIST_HEAD(&its->entry);
     its->base = its_base;
     its->phys_base = its_addr;
+    its->phys_size = its_size;
     its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
 
     its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 08e9787..4babb2a 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -38,6 +38,22 @@
 #include <asm/vgic.h>
 #include <asm/gic-its.h>
 
+/* GITS register definitions */
+#define VITS_GITS_TYPER_HCC       (0xffU << 24)
+#define VITS_GITS_TYPER_PTA_SHIFT (19)
+#define VITS_GITS_DEV_BITS        (0x14U << 13)
+#define VITS_GITS_ID_BITS         (0x13U << 8)
+#define VITS_GITS_ITT_SIZE        (0x7U << 4)
+#define VITS_GITS_DISTRIBUTED     (0x1U << 3)
+#define VITS_GITS_PLPIS           (0x1U << 0)
+
+/* GITS_PIDRn register values for ARM implementations */
+#define GITS_PIDR0_VAL            (0x94)
+#define GITS_PIDR1_VAL            (0xb4)
+#define GITS_PIDR2_VAL            (0x3b)
+#define GITS_PIDR3_VAL            (0x00)
+#define GITS_PIDR4_VAL            (0x04)
+
 //#define DEBUG_ITS
 
 #ifdef DEBUG_ITS
@@ -157,6 +173,829 @@ void its_lpi_free(struct its_lpi_chunk *chunk)
     xfree(chunk);
 }
 
+void vgic_its_disable_lpis(struct vcpu *v, uint32_t lpi)
+{
+    struct pending_irq *p;
+    unsigned long flags;
+
+    p = irq_to_pending(v, lpi);
+    clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+    gic_remove_from_queues(v, lpi);
+    if ( p->desc != NULL )
+    {
+        spin_lock_irqsave(&p->desc->lock, flags);
+        p->desc->handler->disable(p->desc);
+        spin_unlock_irqrestore(&p->desc->lock, flags);
+    }
+}
+
+void vgic_its_enable_lpis(struct vcpu *v, uint32_t lpi)
+{
+    struct pending_irq *p;
+    unsigned long flags;
+
+    p = irq_to_pending(v, lpi);
+    set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+
+    spin_lock_irqsave(&v->arch.vgic.lock, flags);
+
+    if ( !list_empty(&p->inflight) &&
+         !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
+        gic_raise_guest_irq(v, p->desc->virq, p->priority);
+
+    spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+    if ( p->desc != NULL )
+    {
+        spin_lock_irqsave(&p->desc->lock, flags);
+        p->desc->handler->enable(p->desc);
+        spin_unlock_irqrestore(&p->desc->lock, flags);
+    }
+}
+
+static int its_alloc_device_irq(struct vits_device *dev, uint32_t id,
+                                uint32_t *plpi, uint32_t vlpi, uint32_t vcol_id)
+{
+    struct its_lpi_chunk *chunk;
+    int idx, i;
+
+    /* Check device irq list before allocating new lpi chunk */
+    list_for_each_entry( chunk, &dev->hwirq_list, entry )
+    {
+        /* Check if device has entry for this vlpi. If so return the old plpi */
+        for ( i = 0; i < IRQ_PER_CHUNK; i++ )
+        {
+            if ( chunk->vid[i] == vlpi && chunk->vcol_id[i] == vcol_id )
+            {
+                 *plpi = chunk->pid[i];
+                 DPRINTK("Found plpi %d for device 0x%x with vlpi %d id %d\n",
+                          *plpi, dev->dev_id, vlpi, chunk->id[i]);
+                 return 0;
+            }
+        }
+    }
+
+    chunk = list_first_entry_or_null(&dev->hwirq_list,
+                                     struct its_lpi_chunk, entry);
+again:
+    if ( !chunk )
+    {   /* No allocated chunk */
+        chunk = its_lpi_alloc();
+        if (!chunk)
+            return -ENOSPC;
+        list_add(&chunk->entry, &dev->hwirq_list);
+        DPRINTK("vITS: New LPI chunk added to device 0x%x\n", dev->dev_id);
+    }
+
+    idx = find_first_zero_bit(&chunk->lpi_map, IRQS_PER_CHUNK);
+    if ( idx == IRQS_PER_CHUNK )
+    { /* Need to allocate a new chunk */
+        chunk = NULL;
+        goto again;
+    }
+
+    set_bit(idx, &chunk->lpi_map);
+
+    DPRINTK("vITS: LPI chunk base %d chunk map 0x%lx for idx %d added to device 0x%x\n",
+             chunk->lpi_base, chunk->lpi_map, idx, dev->dev_id);
+    /* hwirq is free plpi allocated */
+    *plpi = chunk->lpi_base + idx;
+
+    chunk->pid[idx] = *plpi;
+    chunk->vid[idx] = vlpi;
+    chunk->id[idx]  = id;
+    chunk->vcol_id[idx] = vcol_id;
+
+    DPRINTK("Allocated plpi %d for device 0x%x with vlpi %d id %d\n",
+            *plpi, dev->dev_id, vlpi, id);
+
+    return 0;
+}
+
+/* Should be called with its lock held */
+static void vgic_its_unmap_id(struct vcpu *v, struct vits_device *dev,
+                              uint32_t id, int trash)
+{
+    struct its_lpi_chunk *chunk;
+    int i;
+
+    DPRINTK("vITS: unmap id for device 0x%x id %d trash %d\n",
+             dev->dev_id, id, trash);
+    list_for_each_entry( chunk, &dev->hwirq_list, entry )
+    {
+        for ( i = 0; i < IRQS_PER_CHUNK; i++ )
+        {
+            /* If trash is set. ignore vid check */
+            if ( (chunk->id[i] == id || trash)
+                 && test_bit(i, &chunk->lpi_map) )
+            {
+                DPRINTK("vITS: un mapped id for device 0x%x id %d lpi %d\n",
+                        dev->dev_id, id, chunk->pid[i]);
+                vgic_its_disable_lpis(v, chunk->pid[i]);
+                release_irq(chunk->pid[i], v->domain);
+                chunk->pid[i] = 0;
+                chunk->id[i] = 0;
+                chunk->vcol_id[i] = 0;
+                clear_bit(i, &chunk->lpi_map);
+                goto out;
+            }
+        }
+    }
+
+    dprintk(XENLOG_ERR, "vITS: id %d not found for device 0x%x to unmap\n",
+           id, dev->dev_id);
+    return;
+out:
+    if ( bitmap_empty(&chunk->lpi_map, IRQS_PER_CHUNK) )
+    {
+        list_del(&chunk->entry);
+        DPRINTK("vITS: Freeing lpi chunk\n");
+        its_lpi_free(chunk);
+    }
+    /* XXX: Device entry is not removed on empty lpi list */
+}
+
+static int vgic_its_check_device_id(struct vits_device *dev, uint32_t id)
+{
+    struct its_lpi_chunk *chunk;
+    int i;
+
+    list_for_each_entry( chunk, &dev->hwirq_list, entry )
+    {
+        for ( i = 0; i < IRQS_PER_CHUNK; i++ )
+        {
+            if ( test_bit(i, &chunk->lpi_map) && chunk->id[i] == id )
+                return 0;
+        }
+    }
+
+    return 1;
+}
+
+static int vgic_its_check_vid_entry(struct vcpu *v, uint32_t vid)
+{
+    struct domain *d = v->domain;
+    struct vits_device *dev;
+    struct its_lpi_chunk *chunk;
+    int i;
+
+    list_for_each_entry(dev, &d->arch.vits->vits_dev_list, entry)
+    {
+        list_for_each_entry( chunk, &dev->hwirq_list, entry )
+        {
+            for ( i = 0; i < IRQS_PER_CHUNK; i++ )
+            {
+                if ( chunk->vid[i] == vid )
+                {
+                    DPRINTK("vITS: Found vid entry %d for device 0x%x\n",
+                            vid, dev->dev_id);
+                    return 0;
+                }
+            }
+        }
+    }
+    DPRINTK("vITS: Not found vid entry %d for any device\n", vid);
+
+    return 1;
+}
+
+static struct vits_device * vgic_its_check_device(struct vcpu *v, int dev_id)
+{
+    struct domain *d = v->domain;
+    struct vits_device *dev = NULL, *tmp;
+
+    list_for_each_entry(tmp, &d->arch.vits->vits_dev_list, entry)
+    {
+        if ( tmp->dev_id == dev_id )
+        {
+            DPRINTK("vITS: Found device 0x%x\n", dev_id);
+            dev = tmp;
+            break;
+        }
+    }
+
+    return dev;
+}
+
+static int vgic_its_check_cid(struct vcpu *v, uint8_t vcid, uint32_t *pcid)
+{
+    struct domain *d = v->domain;
+    uint32_t nmap = d->arch.vits->cid_map.nr_cid;
+    int i;
+
+    for ( i = 0; i < nmap; i++ )
+    {
+        if ( vcid == d->arch.vits->cid_map.vcid[i] )
+        {
+            *pcid = d->arch.vits->cid_map.pcid[i];
+            DPRINTK("vITS: Found vcid %d for vcid %d\n", *pcid,
+                     d->arch.vits->cid_map.vcid[i]);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static uint64_t vgic_its_get_pta(struct vcpu *v, uint64_t vta)
+{
+
+    struct domain *d = v->domain;
+    uint32_t nmap = d->arch.vits->cid_map.nr_cid;
+    int i;
+    uint8_t pcid;
+    uint64_t pta;
+
+    for ( i = 0; i < nmap; i++ )
+    {
+        if ( vta == d->arch.vits->cid_map.vta[i] )
+        {
+            pcid = d->arch.vits->cid_map.pcid[i];
+            DPRINTK("vITS: Found vcid %d for vta 0x%lx\n", pcid,
+                     d->arch.vits->cid_map.vta[i]);
+            if ( its_get_target(pcid, &pta) )
+                BUG_ON(1);
+            return pta;
+        }
+    }
+
+    BUG_ON(1);
+    return 1;
+}
+
+static int vgic_its_build_mapd_cmd(struct vcpu *v,
+                                    struct its_cmd_block *virt_cmd,
+                                    struct its_cmd_block *phys_cmd)
+{
+    unsigned long itt_addr;
+
+    itt_addr = its_decode_itt(virt_cmd);
+    /* Get ITT PA from ITT IPA */
+    itt_addr = p2m_lookup(v->domain, itt_addr, NULL);
+    its_encode_cmd(phys_cmd, GITS_CMD_MAPD);
+    its_encode_devid(phys_cmd, its_decode_devid(v->domain, virt_cmd));
+    its_encode_size(phys_cmd, its_decode_size(virt_cmd));
+    its_encode_itt(phys_cmd, itt_addr);
+    its_encode_valid(phys_cmd, its_decode_valid(virt_cmd));
+
+    DPRINTK("vITS: Build MAPD with itt_addr 0x%lx devId %d\n",itt_addr,
+            its_decode_devid(v->domain, virt_cmd));
+
+    return 0;
+}
+
+static int vgic_its_build_sync_cmd(struct vcpu *v,
+                                   struct its_cmd_block *virt_cmd,
+                                   struct its_cmd_block *phys_cmd)
+{
+    uint64_t pta;
+
+    its_encode_cmd(phys_cmd, GITS_CMD_SYNC);
+
+    if ( is_hardware_domain(current->domain) )
+    {
+        if ( its_check_target(its_decode_target(virt_cmd)) )
+        {
+            dprintk(XENLOG_ERR, "vITS: SYNC: Wrong Target Address\n");
+            return 1;
+        }
+        its_encode_target(phys_cmd, its_decode_target(virt_cmd));
+    }
+    else
+    {
+        pta = vgic_its_get_pta(v, its_decode_target(virt_cmd));
+        its_encode_target(phys_cmd, pta);
+    }
+
+    return 0;
+}
+static int vgic_its_build_mapvi_cmd(struct vcpu *v,
+                                    struct its_cmd_block *virt_cmd,
+                                    struct its_cmd_block *phys_cmd)
+{
+    struct domain *d = v->domain;
+    struct vits_device *dev;
+    uint32_t pcol_id;
+    uint32_t pid;
+    struct irq_desc *desc;
+    uint32_t dev_id = its_decode_devid(v->domain,virt_cmd);
+    uint32_t id = its_decode_event_id(virt_cmd);
+    uint8_t vcol_id = its_decode_collection(virt_cmd);
+    uint32_t vid = its_decode_phys_id(virt_cmd);
+    uint8_t cmd = its_decode_cmd(virt_cmd);
+
+    DPRINTK("vITS: MAPVI: dev_id 0x%x vcol_id %d vid %d \n",
+             dev_id, vcol_id, vid);
+
+    /* Search if device entry exists */
+    dev = vgic_its_check_device(v, dev_id);
+    if ( dev == NULL )
+    {
+        dprintk(XENLOG_ERR, "vITS: MAPVI: Fail to find device 0x%x\n", dev_id);
+        return 1;
+    }
+
+    /* Check if Collection id exists */
+    if ( vgic_its_check_cid(v, vcol_id, &pcol_id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: MAPVI: with wrong Collection %d\n", vcol_id);
+        return 1;
+    }
+
+    /* Check if PID is exists for this VID by any device on this domain */
+    if ( !vgic_its_check_vid_entry(v, vid) )
+    {
+        dprintk(XENLOG_ERR, "vITS: MAPVI: with wrong vID %d\n", vid);
+        return 1;
+    }
+    if ( its_alloc_device_irq(dev, id, &pid, vid, vcol_id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: MAPVI: Failed to alloc irq\n");
+        return 1;
+    }
+
+    route_irq_to_guest(d, pid, "LPI");
+
+    desc = irq_to_desc(pid);
+
+     /* Assign device structure to desc data */
+    desc->data = dev;
+    desc->virq = vid;
+
+    its_encode_cmd(phys_cmd, GITS_CMD_MAPVI);
+    its_encode_devid(phys_cmd, dev_id);
+
+    if ( cmd == GITS_CMD_MAPI )
+        its_encode_id(phys_cmd, vid);
+    else
+        its_encode_id(phys_cmd, its_decode_event_id(virt_cmd));
+
+    its_encode_phys_id(phys_cmd, pid);
+    its_encode_collection(phys_cmd, pcol_id);
+
+    return 0;
+}
+
+static int vgic_its_build_movi_cmd(struct vcpu *v,
+                                   struct its_cmd_block *virt_cmd,
+                                   struct its_cmd_block *phys_cmd)
+{
+    uint32_t pcol_id;
+    struct vits_device *dev;
+    uint32_t dev_id = its_decode_devid(v->domain, virt_cmd);
+    uint8_t vcol_id = its_decode_collection(virt_cmd);
+    uint32_t id = its_decode_event_id(virt_cmd);
+
+    DPRINTK("vITS: MOVI: dev_id 0x%x vcol_id %d\n", dev_id, vcol_id);
+    /* Search if device entry exists */
+    dev = vgic_its_check_device(v, dev_id);
+    if ( dev == NULL )
+    {
+        dprintk(XENLOG_ERR, "vITS: MOVI: Failed to find device 0x%x\n", dev_id);
+        return 1;
+    }
+
+    /* Check if Collection id exists */
+    if ( vgic_its_check_cid(v, vcol_id, &pcol_id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: MOVI: with wrong Collection %d\n", vcol_id);
+        return 1;
+    }
+
+    if ( vgic_its_check_device_id(dev, id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: MOVI: Invalid ID %d\n", id);
+        return 1;
+    }
+
+    its_encode_cmd(phys_cmd, GITS_CMD_MOVI);
+    its_encode_devid(phys_cmd, dev_id);
+    its_encode_id(phys_cmd, id);
+    its_encode_collection(phys_cmd, pcol_id);
+
+    return 0;
+}
+
+
+static int vgic_its_build_discard_cmd(struct vcpu *v,
+                                      struct its_cmd_block *virt_cmd,
+                                      struct its_cmd_block *phys_cmd)
+{
+    struct vits_device *dev;
+    uint32_t id = its_decode_event_id(virt_cmd);
+    uint32_t dev_id = its_decode_devid(v->domain, virt_cmd);
+
+    DPRINTK("vITS: DISCARD: dev_id 0x%x id %d\n", dev_id, id);
+    /* Search if device entry exists */
+    dev = vgic_its_check_device(v, dev_id);
+    if ( dev == NULL )
+    {
+        dprintk(XENLOG_ERR, "vITS: DISCARD: Failed to find device 0x%x\n",
+                dev_id);
+        return 1;
+    }
+
+    if ( vgic_its_check_device_id(dev, id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: DISCARD: Invalid vID %d\n", id);
+        return 1;
+    }
+
+    /* Check if PID is exists for this VID for this device and unmap it */
+    vgic_its_unmap_id(v, dev, id, 0);
+
+    /* Fetch and encode cmd */
+    its_encode_cmd(phys_cmd, GITS_CMD_DISCARD);
+    its_encode_devid(phys_cmd, its_decode_devid(v->domain, virt_cmd));
+    its_encode_id(phys_cmd, its_decode_event_id(virt_cmd));
+
+    return 0;
+}
+
+static int vgic_its_build_inv_cmd(struct vcpu *v,
+                                  struct its_cmd_block *virt_cmd,
+                                  struct its_cmd_block *phys_cmd)
+{
+    struct vits_device *dev;
+    uint32_t dev_id = its_decode_devid(v->domain, virt_cmd);
+    uint32_t id = its_decode_event_id(virt_cmd);
+
+    DPRINTK("vITS: INV: dev_id 0x%x id %d\n",dev_id, id);
+    /* Search if device entry exists */
+    dev = vgic_its_check_device(v, dev_id);
+    if ( dev == NULL )
+    {
+        dprintk(XENLOG_ERR, "vITS: INV: Failed to find device 0x%x\n", dev_id);
+        return 1;
+    }
+
+    if ( vgic_its_check_device_id(dev, id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: INV: Invalid ID %d\n", id);
+        return 1;
+    }
+
+    its_encode_cmd(phys_cmd, GITS_CMD_INV);
+    its_encode_devid(phys_cmd, dev_id);
+    its_encode_id(phys_cmd, id);
+
+    return 0;
+}
+
+static int vgic_its_build_clear_cmd(struct vcpu *v,
+                                    struct its_cmd_block *virt_cmd,
+                                    struct its_cmd_block *phys_cmd)
+{
+    struct vits_device *dev;
+    uint32_t dev_id = its_decode_devid(v->domain, virt_cmd);
+    uint32_t id = its_decode_event_id(virt_cmd);
+
+    DPRINTK("vITS: CLEAR: dev_id 0x%x id %d\n", dev_id, id);
+    /* Search if device entry exists */
+    dev = vgic_its_check_device(v, dev_id);
+    if ( dev == NULL )
+    {
+        dprintk(XENLOG_ERR, "vITS: CLEAR: Fail to find device 0x%x\n", dev_id);
+        return 1;
+    }
+
+    if ( vgic_its_check_device_id(dev, id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: CLEAR: Invalid ID %d\n", id);
+        return 1;
+    }
+
+    its_encode_cmd(phys_cmd, GITS_CMD_INV);
+    its_encode_id(phys_cmd, id);
+
+    return 0;
+}
+
+static int vgic_its_build_invall_cmd(struct vcpu *v,
+                                     struct its_cmd_block *virt_cmd,
+                                     struct its_cmd_block *phys_cmd)
+{
+    uint32_t pcol_id;
+    uint8_t vcol_id = its_decode_collection(virt_cmd);
+
+    DPRINTK("vITS: INVALL: vCID %d\n", vcol_id);
+    /* Check if Collection id exists */
+    if ( vgic_its_check_cid(v, vcol_id, &pcol_id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: INVALL: Wrong Collection %d\n", vcol_id);
+        return 1;
+    }
+
+    its_encode_cmd(phys_cmd, GITS_CMD_INVALL);
+    its_encode_collection(phys_cmd, pcol_id);
+
+    return 0;
+}
+
+static int vgic_its_build_int_cmd(struct vcpu *v,
+                                  struct its_cmd_block *virt_cmd,
+                                  struct its_cmd_block *phys_cmd)
+{
+    uint32_t dev_id = its_decode_devid(v->domain, virt_cmd);
+    struct vits_device *dev;
+    uint32_t id = its_decode_event_id(virt_cmd);
+
+    DPRINTK("vITS: INT: Device 0x%x id %d\n", its_decode_devid(v->domain, virt_cmd), id);
+    /* Search if device entry exists */
+    dev = vgic_its_check_device(v, dev_id);
+    if ( dev == NULL )
+    {
+        dprintk(XENLOG_ERR, "vITS: INT: Failed to find device 0x%x\n", dev_id);
+        return 1;
+    }
+
+    if ( vgic_its_check_device_id(dev, id) )
+    {
+        dprintk(XENLOG_ERR, "vITS: INT: Invalid ID %d\n", id);
+        return 1;
+    }
+
+    its_encode_cmd(phys_cmd, GITS_CMD_INT);
+    its_encode_devid(phys_cmd, its_decode_devid(v->domain, virt_cmd));
+    its_encode_id(phys_cmd, its_decode_event_id(virt_cmd));
+
+    return 0;
+}
+
+static void vgic_its_free_device(struct vits_device *dev)
+{
+        xfree(dev);
+}
+
+static int vgic_its_add_device(struct vcpu *v, struct its_cmd_block *virt_cmd)
+{
+    struct domain *d = v->domain;
+    struct vits_device *dev;
+
+    /* Allocate device only if valid bit is set */
+    if ( its_decode_valid(virt_cmd) )
+    {
+        dev = xzalloc(struct vits_device);
+        if ( dev == NULL )
+           return ENOMEM;
+
+        dev->dev_id = its_decode_devid(d, virt_cmd);
+        dev->itt_size = its_decode_size(virt_cmd);
+        dev->itt_addr = its_decode_itt(virt_cmd);
+        INIT_LIST_HEAD(&dev->entry);
+        INIT_LIST_HEAD(&dev->hwirq_list);
+
+        list_add(&dev->entry, &d->arch.vits->vits_dev_list);
+        DPRINTK("vITS: Added device dev_id 0x%x\n", its_decode_devid(v->domain, virt_cmd));
+    }
+    else
+    {
+        /* Search if device entry exists */
+        dev = vgic_its_check_device(v, its_decode_devid(v->domain, virt_cmd));
+        if ( dev == NULL )
+        {
+            dprintk(XENLOG_ERR, "vITS: Failed to find device 0x%x\n",
+                    dev->dev_id);
+            return 1;
+        }
+
+        /* Clear all lpis of this device */
+        vgic_its_unmap_id(v, dev, 0, 1);
+
+        list_del(&dev->entry);
+        vgic_its_free_device(dev);
+        DPRINTK("vITS: Removed device dev_id 0x%x\n", its_decode_devid(v->domain, virt_cmd));
+    }
+
+    return 0;
+}
+
+static int vgic_its_process_mapc(struct vcpu *v, struct its_cmd_block *virt_cmd)
+{
+    uint32_t pcid = 0;
+    int idx;
+    struct domain *d = v->domain;
+    uint32_t nmap;
+    uint8_t vcol_id;
+    uint64_t vta = 0;
+
+    nmap = d->arch.vits->cid_map.nr_cid;
+    vcol_id = its_decode_collection(virt_cmd);
+    vta = its_decode_target(virt_cmd);
+
+    for ( idx = 0; idx < nmap; idx++ )
+    {
+        if ( vcol_id == d->arch.vits->cid_map.vcid[idx] )
+            break;
+    }
+    if ( idx == nmap )
+        d->arch.vits->cid_map.vcid[idx] = vcol_id;
+
+    /* Add new entry */
+    if ( is_hardware_domain(d) )
+    {
+        if ( its_get_physical_cid(&pcid, vta) )
+            BUG_ON(1);
+        d->arch.vits->cid_map.pcid[idx] = pcid;
+        d->arch.vits->cid_map.vta[idx] = vta;
+        d->arch.vits->cid_map.nr_cid++;
+    }
+    else
+    {
+        /* For domU vta != pta so set vcid = pcid.
+           No need to check against pcid mapping from physical its driver.
+         */
+        d->arch.vits->cid_map.pcid[idx] = vcol_id;
+        d->arch.vits->cid_map.vta[idx] = vta;
+        d->arch.vits->cid_map.nr_cid++;
+    }
+
+    DPRINTK("vITS: MAPC: vCID %d vTA 0x%lx added @idx 0x%x \n",
+             vcol_id, vta, idx);
+    return 0;
+}
+
+static void vgic_its_update_read_ptr(struct vcpu *v)
+{
+    v->domain->arch.vits->cmd_read = v->domain->arch.vits->cmd_write;
+}
+
+#ifdef DEBUG_ITS
+char *cmd_str[] = {
+        [GITS_CMD_MOVI]    = "MOVI",
+        [GITS_CMD_INT]     = "INT",
+        [GITS_CMD_CLEAR]   = "CLEAR",
+        [GITS_CMD_SYNC]    = "SYNC",
+        [GITS_CMD_MAPD]    = "MAPD",
+        [GITS_CMD_MAPC]    = "MAPC",
+        [GITS_CMD_MAPVI]   = "MAPVI",
+        [GITS_CMD_MAPI]    = "MAPI",
+        [GITS_CMD_INV]     = "INV",
+        [GITS_CMD_INVALL]  = "INVALL",
+        [GITS_CMD_MOVALL]  = "MOVALL",
+        [GITS_CMD_DISCARD] = "DISCARD",
+    };
+#endif
+static int vgic_its_parse_its_command(struct vcpu *v,
+                                      struct its_cmd_block *virt_cmd)
+{
+    uint8_t cmd = its_decode_cmd(virt_cmd);
+    struct its_cmd_block phys_cmd;
+    int send_flag = 1, ret;
+
+#ifdef DEBUG_ITS
+    DPRINTK("vITS: Received cmd %s (0x%x)\n", cmd_str[cmd], cmd);
+    DPRINTK("Dump Virt cmd: ");
+    dump_cmd(virt_cmd);
+#endif
+
+    memset(&phys_cmd, 0x0, sizeof(struct its_cmd_block));
+    switch ( cmd )
+    {
+    case GITS_CMD_MAPD:
+        /* create virtual device entry */
+        if ( vgic_its_add_device(v, virt_cmd) )
+            return ENODEV;
+        ret = vgic_its_build_mapd_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_MAPC:
+        /* Physical ITS driver already mapped physical Collection */
+        send_flag = 0;
+        ret =  vgic_its_process_mapc(v, virt_cmd);
+        break;
+    case GITS_CMD_MAPI:
+        /* MAPI is same as MAPVI */
+    case GITS_CMD_MAPVI:
+        ret = vgic_its_build_mapvi_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_MOVI:
+        ret = vgic_its_build_movi_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_DISCARD:
+        ret = vgic_its_build_discard_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_INV:
+        ret = vgic_its_build_inv_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_INVALL:
+        ret = vgic_its_build_invall_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_INT:
+        ret = vgic_its_build_int_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_CLEAR:
+        ret = vgic_its_build_clear_cmd(v, virt_cmd, &phys_cmd);
+        break;
+    case GITS_CMD_SYNC:
+        ret = vgic_its_build_sync_cmd(v, virt_cmd, &phys_cmd);
+        break;
+        /*TODO:  GITS_CMD_MOVALL not implemented */
+    default:
+       dprintk(XENLOG_ERR, "vITS: Unhandled command cmd %d\n", cmd);
+       return 1;
+    }
+
+#ifdef DEBUG_ITS
+    DPRINTK("Dump Phys cmd: ");
+    dump_cmd(&phys_cmd);
+#endif
+
+    if ( ret )
+    {
+       dprintk(XENLOG_ERR, "vITS: Failed to handle cmd %d\n", cmd);
+       return 1;
+    }
+
+    if ( send_flag )
+    {
+       if ( !gic_its_send_cmd(v, &phys_cmd) )
+       {
+           dprintk(XENLOG_ERR, "vITS: Failed to push cmd %d\n", cmd);
+           return 1;
+       }
+    }
+
+    return 0;
+}
+/* Called with its lock held */
+static int vgic_its_read_virt_cmd(struct vcpu *v,
+                                  struct its_cmd_block *virt_cmd)
+{
+    struct page_info * page;
+    void *p;
+    paddr_t paddr;
+    paddr_t maddr = v->domain->arch.vits->cmd_base & 0xfffffffff000UL;
+    uint64_t offset;
+
+    /* CMD Q can be more than 1 page. Map only page that is required */
+    maddr = ((v->domain->arch.vits->cmd_base & 0xfffffffff000UL) +
+              v->domain->arch.vits->cmd_write_save ) & PAGE_MASK;
+
+    paddr = p2m_lookup(v->domain, maddr, NULL);
+
+    DPRINTK("vITS: Mapping CMD Q maddr 0x%lx paddr 0x%lx write_save 0x%lx \n",
+            maddr, paddr, v->domain->arch.vits->cmd_write_save);
+    page = get_page_from_paddr(v->domain, paddr, 0);
+    if ( page == NULL )
+    {
+        dprintk(XENLOG_ERR, "vITS: Failed to get command page\n");
+        return 1;
+    }
+
+    p = __map_domain_page(page);
+
+    /* Offset within the mapped 4K page to read */
+    offset = v->domain->arch.vits->cmd_write_save & 0xfff;
+
+    memcpy(virt_cmd, p + offset, sizeof(struct its_cmd_block));
+
+    /* No command queue is created by vits to check on Q full */
+    v->domain->arch.vits->cmd_write_save += 0x20;
+    if ( v->domain->arch.vits->cmd_write_save ==
+         v->domain->arch.vits->cmd_qsize )
+    {
+         DPRINTK("vITS: Reset write_save 0x%lx qsize 0x%lx \n",
+                 v->domain->arch.vits->cmd_write_save,
+                 v->domain->arch.vits->cmd_qsize);
+         v->domain->arch.vits->cmd_write_save = 0x0;
+    }
+
+    unmap_domain_page(p);
+    put_page(page);
+
+    return 0;
+}
+
+int vgic_its_process_cmd(struct vcpu *v)
+{
+    struct its_cmd_block virt_cmd;
+    struct domain *d = v->domain;
+
+    /* XXX: Currently we are processing one cmd at a time */
+    ASSERT(spin_is_locked(&d->arch.vits->lock));
+
+    do {
+        if ( vgic_its_read_virt_cmd(v, &virt_cmd) )
+            goto err;
+        if ( vgic_its_parse_its_command(v, &virt_cmd) )
+            goto err;
+    } while ( v->domain->arch.vits->cmd_write !=
+              v->domain->arch.vits->cmd_write_save );
+
+    v->domain->arch.vits->cmd_write_save = v->domain->arch.vits->cmd_write;
+    DPRINTK("vITS: write_save 0x%lx write 0x%lx \n",
+            v->domain->arch.vits->cmd_write_save,
+            v->domain->arch.vits->cmd_write);
+    /* XXX: Currently we are processing one cmd at a time */
+    vgic_its_update_read_ptr(v);
+
+    dsb(ishst);
+
+    return 1;
+err:
+    dprintk(XENLOG_ERR, "vITS: Failed to process guest cmd\n");
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 9018c6a..d02c200 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -109,6 +109,8 @@ struct arch_domain
 #endif
     } vgic;
 
+    struct vgic_its *vits;
+
     struct vuart {
 #define VUART_BUF_SIZE 128
         char                        *buf;
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 2fca1ef..0b2f95e 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -24,6 +24,67 @@
 
 #define IRQ_PER_CHUNK 32
 
+/* ITS device structure */
+struct vits_device
+{
+    struct list_head entry;
+    /* Device id */
+    uint32_t  dev_id;
+    /* ITT address */
+    paddr_t itt_addr;
+    /* ITT size */
+    unsigned long itt_size;
+    /* LPIs assigned to device */
+    struct list_head hwirq_list;
+};
+
+struct cid_mapping
+{
+    /* Number of collections mapped */
+    uint8_t nr_cid;
+    /* XXX: assume one collection id per vcpu. can set to MAX_VCPUS? */
+    /* Virtual collection id */
+    uint8_t vcid[32];
+    /* Physical collection id */
+    uint8_t pcid[32];
+    /* Virtual target address of this collection id */
+    uint64_t vta[32];
+};
+
+/* Per domain ITS struct */
+struct vgic_its
+{
+   spinlock_t lock;
+   /* Emulation of BASER */
+   paddr_t baser[8];
+   /* Command queue base */
+   paddr_t cmd_base;
+   /* Command queue write pointer */
+   paddr_t cmd_write;
+   /* Command queue write saved pointer */
+   paddr_t cmd_write_save;
+   /* Command queue read pointer */
+   paddr_t cmd_read;
+   /* Command queue size */
+   unsigned long cmd_qsize;
+   /* LPI propbase */
+   paddr_t lpi_propbase;
+   /* percpu pendbase */
+   paddr_t lpi_pendbase[MAX_VIRT_CPUS];
+   /* Virtual LPI property table */
+   void * lpi_prop_page;
+   /* ITS mmio physical base */
+   paddr_t phys_base;
+   /* ITS mmio physical size */
+   unsigned long phys_size;
+   /* gicr ctrl register */
+   uint32_t ctrl;
+   /* Device list. This dev list will hold vlpi, lpi, Devid */
+   struct list_head vits_dev_list;
+   /* Virtual to Physical Collection id mapping */
+   struct cid_mapping cid_map;
+};
+
 /*
  * Our LPI allocation unit - Chunks of 32 IDs
  */
@@ -107,6 +168,12 @@ static inline void its_encode_devid(struct its_cmd_block *cmd, u32 devid)
     cmd->raw_cmd[0] |= ((u64)devid) << 32;
 }
 
+static inline void its_encode_id(struct its_cmd_block *cmd, uint32_t id)
+{
+    cmd->raw_cmd[1] &= ~0xffffffffULL;
+    cmd->raw_cmd[1] |= id;
+}
+
 static inline void its_encode_event_id(struct its_cmd_block *cmd, u32 id)
 {
     cmd->raw_cmd[1] &= ~0xffffffffULL;
@@ -158,6 +225,15 @@ static inline void its_fixup_cmd(struct its_cmd_block *cmd)
     cmd->raw_cmd[3] = cpu_to_le64(cmd->raw_cmd[3]);
 }
 
+void vgic_its_enable_lpis(struct vcpu *v, uint32_t lpi);
+int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid);
+uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
+
+int its_check_target(uint64_t vta);
+int its_get_target(uint8_t pcid, uint64_t *pta);
+int its_get_physical_cid(uint32_t *col_id, uint64_t ta);
+int gic_its_send_cmd(struct vcpu *v, struct its_cmd_block *phys_cmd);
+
 #endif /* __ASM_ARM_GIC_ITS_H__ */
 
 /*
-- 
1.7.9.5

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

* [RFC PATCH 11/19] xen/arm: its: Add emulation of ITS control registers
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (9 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 10/19] xen/arm: its: Add virtual ITS command support vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs vijay.kilari
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Add support for emulating GITS_* registers

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c     |    9 +
 xen/arch/arm/vgic-v3-its.c    |  369 ++++++++++++++++++++++++++++++++++++++++-
 xen/include/asm-arm/gic-its.h |    2 +
 3 files changed, 379 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 68bb7ba..5d9550f 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -68,6 +68,7 @@
 #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING    (1 << 0)
 
 struct its_node *its;
+uint32_t pta_type;
 
 /*
  * Collection structure - just an ID, and a redistributor address to
@@ -139,6 +140,11 @@ struct its_cmd_desc {
 typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
                                 struct its_cmd_desc *);
 
+uint32_t its_get_pta_type(void)
+{
+    return pta_type;
+}
+
 static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
                                                  struct its_cmd_desc *desc)
 {
@@ -764,6 +770,9 @@ static int its_probe(struct dt_device_node *node)
     its->phys_size = its_size;
     its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
 
+    if ( (readq_relaxed(its->base + GITS_TYPER) & GITS_TYPER_PTA) )
+       pta_type = 1;
+
     its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
     if (!its->cmd_base) {
         err = -ENOMEM;
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 4babb2a..7e1cc04 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -965,7 +965,7 @@ static int vgic_its_read_virt_cmd(struct vcpu *v,
     return 0;
 }
 
-int vgic_its_process_cmd(struct vcpu *v)
+static int vgic_its_process_cmd(struct vcpu *v)
 {
     struct its_cmd_block virt_cmd;
     struct domain *d = v->domain;
@@ -996,6 +996,373 @@ err:
     return 0;
 }
 
+static int __vgic_v3_its_ctrl_mmio_read(struct vcpu *v, mmio_info_t *info,
+                                        uint32_t gits_reg)
+{
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+    uint64_t val = 0;
+    uint32_t index;
+
+    switch ( gits_reg )
+    {
+    case GITS_CTLR:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        return 1;
+    case GITS_IIDR:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        return 1;
+    case GITS_TYPER:
+         /* GITS_TYPER support word read */
+        spin_lock(&v->domain->arch.vits->lock);
+        val = ((its_get_pta_type() << VITS_GITS_TYPER_PTA_SHIFT) |
+               VITS_GITS_TYPER_HCC   | VITS_GITS_DEV_BITS |
+               VITS_GITS_ID_BITS     | VITS_GITS_ITT_SIZE |
+               VITS_GITS_DISTRIBUTED | VITS_GITS_PLPIS);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = val;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)(val >> 32);
+        else
+        {
+            spin_unlock(&v->domain->arch.vits->lock);
+            goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+
+    case GITS_TYPER + 4:
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        val = ((its_get_pta_type() << VITS_GITS_TYPER_PTA_SHIFT) |
+               VITS_GITS_TYPER_HCC   | VITS_GITS_DEV_BITS |
+               VITS_GITS_ID_BITS     | VITS_GITS_ITT_SIZE |
+               VITS_GITS_DISTRIBUTED | VITS_GITS_PLPIS);
+        *r = (u32)val;
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case 0x0010 ... 0x007c:
+    case 0xc000 ... 0xffcc:
+        /* Implementation defined -- read ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: read unknown 0x000c - 0x007c r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        goto read_as_zero;
+    case GITS_CBASER:
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->cmd_base && 0xc7ffffffffffffffUL;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)v->domain->arch.vits->cmd_base;
+        else
+        {
+             spin_unlock(&v->domain->arch.vits->lock);
+             goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CBASER + 4:
+         /* CBASER support word read */
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        *r = (u32)(v->domain->arch.vits->cmd_base >> 32);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CWRITER:
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->cmd_write;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)v->domain->arch.vits->cmd_write;
+        else
+        {
+             spin_unlock(&v->domain->arch.vits->lock);
+             goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CWRITER + 4:
+         /* CWRITER support word read */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        *r = (u32)(v->domain->arch.vits->cmd_write >> 32);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CREADR:
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->cmd_read;
+        else if ( dabt.size == DABT_WORD )
+            *r = (u32)v->domain->arch.vits->cmd_read;
+        else
+        {
+             spin_unlock(&v->domain->arch.vits->lock);
+             goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CREADR + 4:
+         /* CREADR support word read */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        *r = (u32)(v->domain->arch.vits->cmd_read >> 32);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case 0x0098 ... 0x009c:
+    case 0x00a0 ... 0x00fc:
+    case 0x0140 ... 0xbffc:
+        /* Reserved -- read ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: read unknown 0x0098-9c or 0x00a0-fc r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        goto read_as_zero;
+    case GITS_BASER ... GITS_BASERN:
+        spin_lock(&v->domain->arch.vits->lock);
+        index = (gits_reg - GITS_BASER) / 8;
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            *r = v->domain->arch.vits->baser[index];
+        else if ( dabt.size == DABT_WORD )
+        {
+            if ( (gits_reg % 8) == 0 )
+                *r = (u32)v->domain->arch.vits->baser[index];
+            else
+                *r = (u32)(v->domain->arch.vits->baser[index] >> 32);
+        }
+        else
+        {
+            spin_unlock(&v->domain->arch.vits->lock);
+            goto bad_width;
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_PIDR0:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR0_VAL;
+        return 1;
+    case GITS_PIDR1:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR1_VAL;
+        return 1;
+    case GITS_PIDR2:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR2_VAL;
+        return 1;
+    case GITS_PIDR3:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR3_VAL;
+        return 1;
+    case GITS_PIDR4:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = GITS_PIDR4_VAL;
+        return 1;
+    case GITS_PIDR5 ... GITS_PIDR7:
+        goto read_as_zero;
+   default:
+        dprintk(XENLOG_G_ERR, "vGITS: unhandled read r%d offset %#08x\n",
+               dabt.reg, gits_reg);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_G_ERR, "vGITS: bad read width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, gits_reg);
+    domain_crash_synchronous();
+    return 0;
+
+read_as_zero:
+    if ( dabt.size != DABT_WORD ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int __vgic_v3_its_ctrl_mmio_write(struct vcpu *v, mmio_info_t *info,
+                                         uint32_t gits_reg)
+{
+    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 ret, index;
+    uint64_t val;
+
+    switch ( gits_reg )
+    {
+    case GITS_CTLR:
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        v->domain->arch.vits->ctrl = *r;
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_IIDR:
+        /* R0 -- write ignored */
+        goto write_ignore;
+    case GITS_TYPER:
+    case GITS_TYPER + 4:
+        /* R0 -- write ignored */
+        goto write_ignore;
+    case 0x0010 ... 0x007c:
+    case 0xc000 ... 0xffcc:
+        /* Implementation defined -- write ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: write to unknown 0x000c - 0x007c r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        goto write_ignore;
+    case GITS_CBASER:
+        if ( dabt.size == DABT_BYTE ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            v->domain->arch.vits->cmd_base = *r;
+        else
+        {
+            val = v->domain->arch.vits->cmd_base & 0xffffffff00000000UL;
+            val = (*r) | val;
+            v->domain->arch.vits->cmd_base =  val;
+        }
+        v->domain->arch.vits->cmd_qsize  =  SZ_4K * ((*r & 0xff) + 1);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CBASER + 4:
+         /* CBASER support word read */
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        val = v->domain->arch.vits->cmd_base & 0xffffffffUL;
+        val = ((*r & 0xffffffffUL) << 32 ) | val;
+        v->domain->arch.vits->cmd_base =  val;
+        /* No Need to update cmd_qsize with higher word write */
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_CWRITER:
+        if ( dabt.size == DABT_BYTE ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            v->domain->arch.vits->cmd_write = *r;
+        else
+        {
+            val = v->domain->arch.vits->cmd_write & 0xffffffff00000000UL;
+            val = (*r) | val;
+            v->domain->arch.vits->cmd_write =  val;
+        }
+        ret = vgic_its_process_cmd(v);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return ret;
+    case GITS_CWRITER + 4:
+        if (dabt.size != DABT_WORD ) goto bad_width;
+        spin_lock(&v->domain->arch.vits->lock);
+        val = v->domain->arch.vits->cmd_write & 0xffffffffUL;
+        val = ((*r & 0xffffffffUL) << 32) | val;
+        v->domain->arch.vits->cmd_write =  val;
+        ret = vgic_its_process_cmd(v);
+        spin_unlock(&v->domain->arch.vits->lock);
+        return ret;
+    case GITS_CREADR:
+        /* R0 -- write ignored */
+        goto write_ignore;
+    case 0x0098 ... 0x009c:
+    case 0x00a0 ... 0x00fc:
+    case 0x0140 ... 0xbffc:
+        /* Reserved -- write ignored */
+        dprintk(XENLOG_G_DEBUG,
+                "vGITS: write to unknown 0x98-9c or 0xa0-fc r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        goto write_ignore;
+    case GITS_BASER ... GITS_BASERN:
+        /* Nothing to do with this values. Just store and emulate */
+        spin_lock(&v->domain->arch.vits->lock);
+        index = (gits_reg - GITS_BASER) / 8;
+        if ( dabt.size == DABT_DOUBLE_WORD )
+            v->domain->arch.vits->baser[index] = *r;
+        else if ( dabt.size == DABT_WORD )
+        {
+            if ( (gits_reg % 8) == 0 )
+            {
+                val = v->domain->arch.vits->cmd_write & 0xffffffff00000000UL;
+                val = (*r) | val;
+                v->domain->arch.vits->baser[index] = val;
+            }
+            else
+            {
+                val = v->domain->arch.vits->baser[index] & 0xffffffffUL;
+                val = ((*r & 0xffffffffUL) << 32) | val;
+                v->domain->arch.vits->baser[index] = val;
+            }
+        }
+        else
+        {
+            goto bad_width;
+            spin_unlock(&v->domain->arch.vits->lock);
+        }
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    case GITS_PIDR7 ... GITS_PIDR0:
+        /* R0 -- write ignored */
+        goto write_ignore;
+   default:
+        dprintk(XENLOG_G_ERR, "vGITS: unhandled write r%d offset %#08x\n",
+                dabt.reg, gits_reg);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_G_ERR, "vGITS: bad write width %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, gits_reg);
+    domain_crash_synchronous();
+    return 0;
+
+write_ignore:
+    if ( dabt.size != DABT_WORD ) goto bad_width;
+    *r = 0;
+    return 1;
+}
+
+static int vgic_v3_gits_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+
+    offset = info->gpa - v->domain->arch.vits->phys_base;
+
+    if ( offset < SZ_64K )
+        return __vgic_v3_its_ctrl_mmio_read(v, info, offset);
+    else
+        gdprintk(XENLOG_G_WARNING, "vGITS: unknown gpa read address \
+                  %"PRIpaddr"\n", info->gpa);
+
+    return 0;
+}
+
+static int vgic_v3_gits_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+
+    offset = info->gpa  - v->domain->arch.vits->phys_base;
+    if ( offset < SZ_64K )
+        return __vgic_v3_its_ctrl_mmio_write(v, info, offset);
+    else
+        gdprintk(XENLOG_G_WARNING, "vGIC-ITS: unknown gpa write address"
+                 " %"PRIpaddr"\n", info->gpa);
+
+    return 0;
+}
+
+static const struct mmio_handler_ops vgic_gits_mmio_handler = {
+    .read_handler  = vgic_v3_gits_mmio_read,
+    .write_handler = vgic_v3_gits_mmio_write,
+};
+
+int vgic_its_domain_init(struct domain *d)
+{
+    d->arch.vits = xzalloc(struct vgic_its);
+    if ( d->arch.vits == NULL )
+        return -ENOMEM;
+
+    INIT_LIST_HEAD(&d->arch.vits->vits_dev_list);
+    spin_lock_init(&d->arch.vits->lock);
+
+    register_mmio_handler(d, &vgic_gits_mmio_handler, d->arch.vits->phys_base,
+                          SZ_64K);
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 0b2f95e..bb9ac33 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -227,10 +227,12 @@ static inline void its_fixup_cmd(struct its_cmd_block *cmd)
 
 void vgic_its_enable_lpis(struct vcpu *v, uint32_t lpi);
 int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid);
+int vgic_its_domain_init(struct domain *d);
 uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
 
 int its_check_target(uint64_t vta);
 int its_get_target(uint8_t pcid, uint64_t *pta);
+uint32_t its_get_pta_type(void);
 int its_get_physical_cid(uint32_t *col_id, uint64_t ta);
 int gic_its_send_cmd(struct vcpu *v, struct its_cmd_block *phys_cmd);
 
-- 
1.7.9.5

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

* [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (10 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 11/19] xen/arm: its: Add emulation of ITS control registers vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-03 17:16   ` Stefano Stabellini
  2015-03-02 12:30 ` [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller " vijay.kilari
                   ` (8 subsequent siblings)
  20 siblings, 1 reply; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

With this patch add emulation of GICR registers for LPIs.
Also add LPI property table emulation.

Domain's LPI property table is unmapped during domain init
on LPIPROPBASE update and trapped on LPI property
table read and write

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/vgic-v3-its.c        |  156 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic-v3.c            |   64 ++++++++++++---
 xen/include/asm-arm/domain.h      |    1 +
 xen/include/asm-arm/gic-its.h     |    1 +
 xen/include/asm-arm/gic.h         |    2 +
 xen/include/asm-arm/gic_v3_defs.h |    2 +
 6 files changed, 214 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 7e1cc04..48c880a 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -996,6 +996,162 @@ err:
     return 0;
 }
 
+/* Search device structure and get corresponding plpi */
+int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid)
+{
+    struct domain *d = v->domain;
+    struct vits_device *dev;
+    struct its_lpi_chunk *chunk;
+    int i;
+
+    list_for_each_entry( dev, &d->arch.vits->vits_dev_list, entry )
+    {
+        list_for_each_entry( chunk, &dev->hwirq_list, entry )
+        {
+            for ( i = 0; i < IRQS_PER_CHUNK; i++ )
+            {
+                if ( test_bit(i, &chunk->lpi_map) && chunk->vid[i] == vid )
+                {
+                    *pid = chunk->pid[i];
+                     return 0;
+                }
+            }
+        }
+    }
+
+    return 1;
+}
+
+static int vgic_v3_gits_lpi_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);
+    uint8_t cfg;
+
+    spin_lock(&v->domain->arch.vits->lock);
+    offset = info->gpa -
+             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
+
+    if ( offset < SZ_64K )
+    {
+        DPRINTK("vITS: LPI Table read offset 0x%x\n", offset );
+        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
+        *r = cfg;
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    }
+    else
+        dprintk(XENLOG_ERR, "vITS: LPI Table read with wrong offset 0x%x\n",
+                offset);
+
+    spin_unlock(&v->domain->arch.vits->lock);
+
+    return 0;
+}
+
+static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset;
+    uint32_t pid, vid;
+    uint8_t cfg;
+    bool_t enable;
+    struct hsr_dabt dabt = info->dabt;
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    register_t *r = select_user_reg(regs, dabt.reg);
+
+    spin_lock(&v->domain->arch.vits->lock);
+    offset = info->gpa -
+             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
+
+    vid = offset + NR_GIC_LPI;
+    if ( offset < SZ_64K )
+    {
+        DPRINTK("vITS: LPI Table write offset 0x%x\n", offset );
+        if ( vgic_its_get_pid(v, vid, &pid) )
+        {
+            spin_unlock(&v->domain->arch.vits->lock);
+            dprintk(XENLOG_ERR, "vITS: pID not found for vid %d\n", vid);
+            return 0;
+        }
+
+        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
+        enable = (cfg & *r) & 0x1;
+
+        if ( !enable )
+             vgic_its_enable_lpis(v, pid);
+        else
+             vgic_its_disable_lpis(v, pid);
+
+        /* Update virtual prop page */
+        writeb_relaxed((*r & 0xff),
+                        v->domain->arch.vits->lpi_prop_page + offset);
+
+        spin_unlock(&v->domain->arch.vits->lock);
+        return 1;
+    }
+    else
+        dprintk(XENLOG_ERR, "vITS: LPI Table write with wrong offset 0x%x\n",
+                offset);
+
+    spin_unlock(&v->domain->arch.vits->lock);
+
+    return 0;
+}
+
+static const struct mmio_handler_ops vgic_gits_lpi_mmio_handler = {
+    .read_handler  = vgic_v3_gits_lpi_mmio_read,
+    .write_handler = vgic_v3_gits_lpi_mmio_write,
+};
+
+int vgic_its_unmap_lpi_prop(struct vcpu *v)
+{
+    paddr_t maddr;
+    uint32_t lpi_size;
+    int i;
+
+    spin_lock(&v->domain->arch.vits->lock);
+    maddr = v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL;
+    lpi_size = 1UL << ((v->domain->arch.vits->lpi_propbase & 0x1f) + 1);
+
+    DPRINTK("vITS: Unmap guest LPI conf table maddr 0x%lx lpi_size 0x%x\n",
+             maddr, lpi_size);
+
+    if ( lpi_size < SZ_64K )
+    {
+        spin_unlock(&v->domain->arch.vits->lock);
+        dprintk(XENLOG_ERR, "vITS: LPI Prop page < 64K\n");
+        return 0;
+    }
+
+    /* XXX: As per 4.8.9 each re-distributor shares a common LPI configuration table
+     * So one set of mmio handlers to manage configuration table is enough
+     */
+    for ( i = 0; i < lpi_size / PAGE_SIZE; i++ )
+        guest_physmap_remove_page(v->domain, paddr_to_pfn(maddr),
+                                gmfn_to_mfn(v->domain, paddr_to_pfn(maddr)), 0);
+
+    /* Register mmio handlers for this region */
+    register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler,
+                          maddr, lpi_size);
+
+    /* Allocate Virtual LPI Property table */
+    v->domain->arch.vits->lpi_prop_page =
+        alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0);
+    if ( !v->domain->arch.vits->lpi_prop_page )
+    {
+        spin_unlock(&v->domain->arch.vits->lock);
+        dprintk(XENLOG_ERR, "vITS: Failed to allocate LPI Prop page\n");
+        return 0;
+    }
+
+    memset(v->domain->arch.vits->lpi_prop_page, 0xa2, lpi_size);
+    spin_unlock(&v->domain->arch.vits->lock);
+
+    return 1;
+}
+
 static int __vgic_v3_its_ctrl_mmio_read(struct vcpu *v, mmio_info_t *info,
                                         uint32_t gits_reg)
 {
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index bece189..89e6195 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -32,6 +32,7 @@
 #include <asm/gic_v3_defs.h>
 #include <asm/gic.h>
 #include <asm/vgic.h>
+#include <asm/gic-its.h>
 
 /* GICD_PIDRn register values for ARM implementations */
 #define GICV3_GICD_PIDR0  0x92
@@ -94,19 +95,29 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
     switch ( gicr_reg )
     {
     case GICR_CTLR:
-        /* We have not implemented LPI's, read zero */
-        goto read_as_zero;
+        /*
+         * Enable LPI's for ITS. Direct injection of LPI
+         * by writing to GICR_{SET,CLR}LPIR are not supported
+         */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        vgic_lock(v);
+        *r = v->domain->arch.vgic.gicr_ctlr;
+        vgic_unlock(v);
+        return 1;
     case GICR_IIDR:
         if ( dabt.size != DABT_WORD ) goto bad_width;
         *r = GICV3_GICR_IIDR_VAL;
         return 1;
     case GICR_TYPER:
-        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
-        /* TBD: Update processor id in [23:8] when ITS support is added */
+        if ( dabt.size != DABT_WORD && dabt.size != DABT_DOUBLE_WORD )
+            goto bad_width;
+        /* XXX: Update processor id in [23:8] if GITS_TYPER: PTA is not set */
         aff = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 56 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 |
                MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32);
+        /* Set LPI support */
+        aff |= (GICR_TYPER_DISTRIBUTED_IMP | GICR_TYPER_PLPIS);
         *r = aff;
         return 1;
     case GICR_STATUSR:
@@ -122,10 +133,13 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
         /* WO. Read as zero */
         goto read_as_zero_64;
     case GICR_PROPBASER:
-        /* LPI's not implemented */
-        goto read_as_zero_64;
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        /* Remove shareability attribute we don't want dom to flush */
+        *r = v->domain->arch.vits->lpi_propbase;
+        return 1;
     case GICR_PENDBASER:
-        /* LPI's not implemented */
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        *r = v->domain->arch.vits->lpi_pendbase[v->vcpu_id];
         goto read_as_zero_64;
     case GICR_INVLPIR:
         /* WO. Read as zero */
@@ -200,8 +214,15 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
     switch ( gicr_reg )
     {
     case GICR_CTLR:
-        /* LPI's not implemented */
-        goto write_ignore;
+        /*
+         * Enable LPI's for ITS. Direct injection of LPI
+         * by writing to GICR_{SET,CLR}LPIR are not supported
+         */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        vgic_lock(v);
+        v->domain->arch.vgic.gicr_ctlr = (*r) & GICR_CTL_ENABLE;
+        vgic_unlock(v);
+        return 1;
     case GICR_IIDR:
         /* RO */
         goto write_ignore;
@@ -221,11 +242,29 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
         /* LPI is not implemented */
         goto write_ignore_64;
     case GICR_PROPBASER:
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        vgic_lock(v);
+        /* LPI configuration tables are shared across cpus. Should be same */
+        if ( (v->domain->arch.vits->lpi_propbase != 0) &&
+             ((v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL) !=  (*r & 0xfffffffff000UL)) )
+        {
+            dprintk(XENLOG_G_ERR,
+                "vGICv3: vITS: Wrong configuration of LPI_PROPBASER\n");
+            vgic_unlock(v);
+            return 0;
+        }
+        v->domain->arch.vits->lpi_propbase = *r;
+        vgic_unlock(v);
+        return vgic_its_unmap_lpi_prop(v);
         /* LPI is not implemented */
         goto write_ignore_64;
     case GICR_PENDBASER:
-        /* LPI is not implemented */
-        goto write_ignore_64;
+        /* Just hold pendbaser value for guest read */
+        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
+        vgic_lock(v);
+        v->domain->arch.vits->lpi_pendbase[v->vcpu_id] = *r;
+        vgic_unlock(v);
+        return 1;
     case GICR_INVLPIR:
         /* LPI is not implemented */
         goto write_ignore_64;
@@ -682,7 +721,8 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
         if ( dabt.size != DABT_WORD ) goto bad_width;
         /* No secure world support for guests. */
         *r = (((v->domain->max_vcpus << 5) & GICD_TYPE_CPUS ) |
-              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES));
+              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES) |
+              GICD_TYPE_LPIS | GICD_TYPE_ID_BITS);
         return 1;
     case GICD_STATUSR:
         /*
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index d02c200..b6d85b8 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -101,6 +101,7 @@ struct arch_domain
         paddr_t cbase; /* CPU base address */
 #ifdef CONFIG_ARM_64
         /* GIC V3 addressing */
+        int gicr_ctlr;
         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 */
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index bb9ac33..5329e9d 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -228,6 +228,7 @@ static inline void its_fixup_cmd(struct its_cmd_block *cmd)
 void vgic_its_enable_lpis(struct vcpu *v, uint32_t lpi);
 int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid);
 int vgic_its_domain_init(struct domain *d);
+int vgic_its_unmap_lpi_prop(struct vcpu *v);
 uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
 
 int its_check_target(uint64_t vta);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 1b4b7d1..681d75c 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -96,6 +96,8 @@
 #define GICD_TYPE_LINES 0x01f
 #define GICD_TYPE_CPUS  0x0e0
 #define GICD_TYPE_SEC   0x400
+#define GICD_TYPE_LPIS           (0x1UL << 17)
+#define GICD_TYPE_ID_BITS        (0x13UL << 19)
 
 #define GICC_CTL_ENABLE 0x1
 #define GICC_CTL_EOI    (0x1 << 9)
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 83d75cf..b81f83f 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -127,9 +127,11 @@
 #define GICR_PROPBASER_RaWaWb		(7U << 7)
 #define GICR_PROPBASER_IDBITS_MASK	(0x1f)
 
+#define GICR_CTL_ENABLE              (1U << 0)
 #define GICR_TYPER_PLPIS             (1U << 0)
 #define GICR_TYPER_VLPIS             (1U << 1)
 #define GICR_TYPER_LAST              (1U << 4)
+#define GICR_TYPER_DISTRIBUTED_IMP   (1U << 3)
 
 #define DEFAULT_PMR_VALUE            0xff
 
-- 
1.7.9.5

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

* [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller for LPIs
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (11 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-03 17:28   ` Stefano Stabellini
  2015-03-02 12:30 ` [RFC PATCH 14/19] xen/arm: vits: Map ITS translation space vijay.kilari
                   ` (7 subsequent siblings)
  20 siblings, 1 reply; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

This patch implements hw_irq_controller api's required
to handle LPI's.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c |  104 ++++++++++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/gic.c        |   11 +++++
 xen/include/asm-arm/gic.h |    8 +++-
 3 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 5d9550f..b2c3320 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -140,6 +140,9 @@ struct its_cmd_desc {
 typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
                                 struct its_cmd_desc *);
 
+static void its_send_movi(struct its_node *its, struct its_collection *col,
+                          u32 dev_id, u32 id);
+
 uint32_t its_get_pta_type(void)
 {
     return pta_type;
@@ -244,6 +247,103 @@ int its_get_physical_cid(uint32_t *col_id, uint64_t vta)
     return 1;
 }
 
+static void lpi_set_config(u32 hwirq, u32 id, int enable)
+{
+    u8 *cfg;
+
+    cfg = gic_rdists->prop_page + hwirq - NR_GIC_LPI;
+
+    if ( enable )
+        *cfg |= (1 << 0);
+    else
+        *cfg &= ~(1 << 0);
+
+    /*
+     * Make the above write visible to the redistributors.
+     * And yes, we're flushing exactly: One. Single. Byte.
+     * Humpf...
+     */
+    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
+        clean_dcache_va_range(cfg, sizeof(*cfg));
+    else
+        dsb(ishst);
+}
+
+static void its_mask_irq(struct irq_desc *d)
+{
+    u32 id;
+
+    id = d->irq;
+    set_bit(_IRQ_DISABLED, &d->status);
+    lpi_set_config(d->irq, id, 0);
+}
+
+static void its_unmask_irq(struct irq_desc *d)
+{
+    u32 id;
+
+    id = d->irq;
+    clear_bit(_IRQ_DISABLED, &d->status);
+    lpi_set_config(d->irq, id, 1);
+}
+
+static unsigned int its_irq_startup(struct irq_desc *desc)
+{
+    its_unmask_irq(desc);
+
+    return 0;
+}
+
+static void its_irq_shutdown(struct irq_desc *desc)
+{
+    its_mask_irq(desc);
+}
+
+static void its_eoi_irq(struct irq_desc *d)
+{
+    gic_eoi_irq(d);
+}
+
+static void its_ack_irq(struct irq_desc *desc)
+{
+    /* No ACK -- reading IAR has done this for us */
+}
+
+static void its_set_affinity(struct irq_desc *d, const cpumask_t *mask_val)
+{
+    /* XXX: check cpumask_any or cpu_online_map is ok? */
+    cpumask_t online_mask;
+    unsigned int cpu;
+    struct vits_device *its_dev = irq_get_desc_data(d);
+    struct its_collection *target_col;
+    uint32_t id;
+
+    cpumask_and(&online_mask, mask_val, &cpu_online_map);
+    cpu = cpumask_any(&online_mask);
+    /* Physical collection id */
+    target_col = &its->collections[cpu];
+    /* Physical irq is considered not virq */
+    id = d->irq;
+
+    its_send_movi(its, target_col, its_dev->dev_id, id);
+}
+
+/* TODO: To implement set_affinity */
+static const hw_irq_controller gic_guest_its_type = {
+    .typename     = "gic-its",
+    .startup      = its_irq_startup,
+    .shutdown     = its_irq_shutdown,
+    .enable       = its_unmask_irq,
+    .disable      = its_mask_irq,
+    .ack          = its_ack_irq,
+    .end          = its_eoi_irq,
+    .set_affinity = its_set_affinity,
+};
+
+static const struct gic_its_hw_operations gic_its_ops = {
+    .gic_guest_lpi_type  = &gic_guest_its_type,
+};
+
 static u64 its_cmd_ptr_to_offset(struct its_node *its,
                                  struct its_cmd_block *ptr)
 {
@@ -392,7 +492,7 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col,
     its_send_single_command(its, its_build_mapc_cmd, &desc);
 }
 
-void its_send_movi(struct its_node *its, struct its_collection *col,
+static void its_send_movi(struct its_node *its, struct its_collection *col,
                    u32 dev_id, u32 id)
 {
     struct its_cmd_desc desc;
@@ -872,6 +972,8 @@ int its_init(struct dt_device_node *node, struct rdist_prop *rdists)
 
     its_alloc_lpi_tables();
 
+    register_gic_its_ops(&gic_its_ops);
+
     return 0;
 }
 
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 390c8b0..fb77387 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -46,12 +46,18 @@ static DEFINE_PER_CPU(uint64_t, lr_mask);
 static void gic_update_one_lr(struct vcpu *v, int i);
 
 static const struct gic_hw_operations *gic_hw_ops;
+static const struct gic_its_hw_operations *gic_its_hw_ops;
 
 void register_gic_ops(const struct gic_hw_operations *ops)
 {
     gic_hw_ops = ops;
 }
 
+void register_gic_its_ops(const struct gic_its_hw_operations *ops)
+{
+    gic_its_hw_ops = ops;
+}
+
 static void clear_cpu_lr_mask(void)
 {
     this_cpu(lr_mask) = 0ULL;
@@ -67,6 +73,11 @@ unsigned int gic_number_lines(void)
     return gic_hw_ops->info->nr_lines;
 }
 
+void gic_eoi_irq(struct irq_desc *d)
+{
+    gic_hw_ops->eoi_irq(d);
+}
+
 void gic_save_state(struct vcpu *v)
 {
     ASSERT(!local_irq_is_enabled());
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 681d75c..eac738f 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -217,7 +217,7 @@ enum gic_version {
 };
 
 extern enum gic_version gic_hw_version(void);
-
+extern void gic_eoi_irq(struct irq_desc *desc);
 /* Program the GIC to route an interrupt */
 extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
                                  unsigned int priority);
@@ -291,6 +291,11 @@ struct gic_info {
     unsigned int maintenance_irq;
 };
 
+struct gic_its_hw_operations {
+    /* LPI hw_irq_controller to enable/disable/eoi host irq */
+    hw_irq_controller *gic_guest_lpi_type;
+};
+
 struct gic_hw_operations {
     /* Hold GIC HW information */
     const struct gic_info *info;
@@ -346,6 +351,7 @@ struct gic_hw_operations {
 };
 
 void register_gic_ops(const struct gic_hw_operations *ops);
+void register_gic_its_ops(const struct gic_its_hw_operations *ops);
 int gic_make_node(const struct domain *d,const struct dt_device_node *node,
                   void *fdt);
 
-- 
1.7.9.5

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

* [RFC PATCH 14/19] xen/arm: vits: Map ITS translation space
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (12 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller " vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-03 17:31   ` Stefano Stabellini
  2015-03-02 12:30 ` [RFC PATCH 15/19] xen/arm: gicv3: Refactor redistributor information vijay.kilari
                   ` (6 subsequent siblings)
  20 siblings, 1 reply; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

ITS translation space contains GITS_TRANSLATOR
register which is written by device to raise
LPI. This space needs to mapped to every domain
address space so that device can access GITS_TRANSLATOR
register using SMMU

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/vgic-v3-its.c |   33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 48c880a..e7e587e 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -1504,7 +1504,35 @@ static const struct mmio_handler_ops vgic_gits_mmio_handler = {
     .write_handler = vgic_v3_gits_mmio_write,
 };
 
-int vgic_its_domain_init(struct domain *d)
+/*
+ * Map the 64K ITS translation space in guest.
+ * This is required purely for device smmu writes.
+ */
+
+static int vgic_map_translation_space(struct domain *d)
+{
+    u64 addr, size;
+    int ret;
+    addr = d->arch.vits->phys_base + SZ_64K;
+    size = SZ_64K;
+
+    ret = map_mmio_regions(d,
+                           paddr_to_pfn(addr & PAGE_MASK),
+                           DIV_ROUND_UP(size, PAGE_SIZE),
+                           paddr_to_pfn(addr & PAGE_MASK));
+
+     if ( ret )
+     {
+          printk(XENLOG_ERR "Unable to map to dom%d access to"
+                 " 0x%"PRIx64" - 0x%"PRIx64"\n",
+                 d->domain_id,
+                 addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1);
+     }
+
+    return ret;
+}
+
+int vgic_its_domain_init(struct domain *d) 
 {
     d->arch.vits = xzalloc(struct vgic_its);
     if ( d->arch.vits == NULL )
@@ -1516,9 +1544,10 @@ int vgic_its_domain_init(struct domain *d)
     register_mmio_handler(d, &vgic_gits_mmio_handler, d->arch.vits->phys_base,
                           SZ_64K);
 
-    return 0;
+    return vgic_map_translation_space(d);
 }
 
+
 /*
  * Local variables:
  * mode: C
-- 
1.7.9.5

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

* [RFC PATCH 15/19] xen/arm: gicv3: Refactor redistributor information
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (13 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 14/19] xen/arm: vits: Map ITS translation space vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 16/19] xen/arm: its: Dynamic allocation of LPI descriptors vijay.kilari
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Separate redistributor information into rdist and rdist_prop
structures.

The rdist_prop holds the redistributor common information
and rdist holds the per cpu specific information.

This percpu rdist defined as global and shared with ITS
driver

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

diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 5c35ac5..02e71dd 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -39,6 +39,7 @@
 #include <asm/device.h>
 #include <asm/gic.h>
 #include <asm/gic_v3_defs.h>
+#include <asm/gic-its.h>
 #include <asm/cpufeature.h>
 
 struct rdist_region {
@@ -52,6 +53,7 @@ static struct {
     paddr_t dbase;            /* Address of distributor registers */
     paddr_t dbase_size;
     void __iomem *map_dbase;  /* Mapped address of distributor registers */
+    struct rdist_prop rdist_data;
     struct rdist_region *rdist_regions;
     uint32_t  rdist_stride;
     unsigned int rdist_count; /* Number of rdist regions count */
@@ -62,11 +64,10 @@ static struct {
 static struct gic_info gicv3_info;
 
 /* per-cpu re-distributor base */
-static DEFINE_PER_CPU(void __iomem*, rbase);
 DEFINE_PER_CPU(struct rdist, rdist);
 
 #define GICD                   (gicv3.map_dbase)
-#define GICD_RDIST_BASE        (this_cpu(rbase))
+#define GICD_RDIST_BASE        (per_cpu(rdist,smp_processor_id()).rbase)
 #define GICD_RDIST_SGI_BASE    (GICD_RDIST_BASE + SZ_64K)
 
 /*
@@ -595,6 +596,7 @@ static int __init gicv3_populate_rdist(void)
     uint32_t aff;
     uint32_t reg;
     uint64_t typer;
+    uint64_t offset;
     uint64_t mpidr = cpu_logical_map(smp_processor_id());
 
     /*
@@ -630,9 +632,12 @@ static int __init gicv3_populate_rdist(void)
 
             if ( (typer >> 32) == aff )
             {
-                this_cpu(rbase) = ptr;
-                printk("GICv3: CPU%d: Found redistributor in region %d @%p\n",
-                        smp_processor_id(), i, ptr);
+                offset = ptr - gicv3.rdist_regions[i].map_base;
+                per_cpu(rdist, smp_processor_id()).rbase = ptr;
+                per_cpu(rdist, smp_processor_id()).phys_base =  gicv3.rdist_regions[i].base + offset;
+                printk("GICv3: CPU%d: Found redistributor in region %d @%"PRIpaddr"\n",
+                        smp_processor_id(), i,
+                        per_cpu(rdist, smp_processor_id()).phys_base);
                 return 0;
             }
             if ( gicv3.rdist_stride )
-- 
1.7.9.5

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

* [RFC PATCH 16/19] xen/arm: its: Dynamic allocation of LPI descriptors
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (14 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 15/19] xen/arm: gicv3: Refactor redistributor information vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling vijay.kilari
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Number of LPIs supported by GICv3 is huge. Boot time
allocation of irq descriptors and pending_irq descritors
is not viable.

With this patch, allocate irq/pending_irq descritors for
LPIs on-demand and manage using radix tree

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/irq.c           |  183 +++++++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/vgic.c          |   20 ++++-
 xen/include/asm-arm/domain.h |    4 +
 xen/include/asm-arm/gic.h    |    2 +
 xen/include/asm-arm/irq.h    |   10 +++
 5 files changed, 214 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index d52ee0c..13583b4 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -30,6 +30,8 @@
 
 static unsigned int local_irqs_type[NR_LOCAL_IRQS];
 static DEFINE_SPINLOCK(local_irqs_type_lock);
+static DEFINE_SPINLOCK(radix_tree_desc_lock);
+static struct radix_tree_root desc_root;
 
 static void ack_none(struct irq_desc *irq)
 {
@@ -51,18 +53,149 @@ hw_irq_controller no_irq_type = {
 static irq_desc_t irq_desc[NR_IRQS];
 static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
 
+static void init_one_irq_data(int irq, struct irq_desc *desc);
+
+struct irq_desc * find_irq_desc(struct radix_tree_root *root_node, int irq)
+{
+    unsigned long flags;
+    struct irq_desc *desc;
+
+    spin_lock_irqsave(&radix_tree_desc_lock, flags);
+    desc = radix_tree_lookup(root_node, irq);
+    spin_unlock_irqrestore(&radix_tree_desc_lock, flags);
+
+    return desc;
+}
+
+struct pending_irq *find_pending_irq_desc(struct domain *d, int irq)
+{
+    unsigned long flags;
+    struct pending_irq *p;
+
+    spin_lock_irqsave(&d->arch.vgic.pending_lpi_lock, flags);
+    p = radix_tree_lookup(&d->arch.vgic.pending_lpis, irq);
+    spin_unlock_irqrestore(&d->arch.vgic.pending_lpi_lock, flags);
+
+    return p;
+}
+
+struct irq_desc *insert_irq_desc(struct radix_tree_root *root_node, int irq)
+{
+    unsigned long flags;
+    struct irq_desc *desc;
+    int ret;
+
+    spin_lock_irqsave(&radix_tree_desc_lock, flags);
+    desc = radix_tree_lookup(root_node, irq);
+    if ( desc == NULL )
+    {
+
+        desc = xzalloc(struct irq_desc);
+        if ( desc == NULL )
+            goto err;
+        init_one_irq_data(irq, desc);
+        ret = radix_tree_insert(root_node, irq, desc);
+        if ( ret )
+        {
+            xfree(desc);
+            goto err;
+        }
+    }
+    spin_unlock_irqrestore(&radix_tree_desc_lock, flags);
+
+    return desc;
+err:
+    spin_unlock_irqrestore(&radix_tree_desc_lock, flags);
+
+    return NULL;
+}
+
+struct pending_irq *insert_pending_irq_desc(struct domain *d, int irq)
+{
+    unsigned long flags;
+    int ret;
+    struct pending_irq *p;
+
+    spin_lock_irqsave(&d->arch.vgic.pending_lpi_lock, flags);
+    p = radix_tree_lookup(&d->arch.vgic.pending_lpis, irq);
+    if ( p == NULL )
+    {
+        if ( (p = xzalloc(struct pending_irq)) == NULL )
+            goto err;
+        ret = radix_tree_insert(&d->arch.vgic.pending_lpis, irq, p);
+        if ( ret )
+        {
+            xfree(p);
+            goto err;
+        }
+        INIT_LIST_HEAD(&p->inflight);
+        INIT_LIST_HEAD(&p->lr_queue);
+    }
+    spin_unlock_irqrestore(&d->arch.vgic.pending_lpi_lock, flags);
+
+    return p;
+err:
+    spin_unlock_irqrestore(&d->arch.vgic.pending_lpi_lock, flags);
+
+    return NULL;
+}
+
+struct irq_desc *delete_irq_desc(struct radix_tree_root *root_node, int irq)
+{
+    unsigned long flags;
+    struct irq_desc *desc;
+
+    spin_lock_irqsave(&radix_tree_desc_lock, flags);
+    desc = radix_tree_delete(root_node, irq);
+    spin_unlock_irqrestore(&radix_tree_desc_lock, flags);
+
+    return desc;
+}
+
+struct pending_irq *delete_pending_irq_desc(struct domain *d, int irq)
+{
+    unsigned long flags;
+    struct pending_irq *p;
+
+    spin_lock_irqsave(&d->arch.vgic.pending_lpi_lock, flags);
+    p = radix_tree_delete(&d->arch.vgic.pending_lpis, irq);
+    spin_unlock_irqrestore(&d->arch.vgic.pending_lpi_lock, flags);
+
+    return p; 
+}
+
 irq_desc_t *__irq_to_desc(int irq)
 {
+    struct irq_desc *desc = NULL;
+
     if (irq < NR_LOCAL_IRQS) return &this_cpu(local_irq_desc)[irq];
-    return &irq_desc[irq-NR_LOCAL_IRQS];
+    else if ( irq >= NR_LOCAL_IRQS && irq < NR_IRQS)
+        return &irq_desc[irq-NR_LOCAL_IRQS];
+    else
+    {
+        if ( is_lpi(irq) )
+            desc = find_irq_desc(&desc_root, irq);
+        else
+            BUG();
+    }
+
+    return desc;
 }
 
-int __init arch_init_one_irq_desc(struct irq_desc *desc)
+int arch_init_one_irq_desc(struct irq_desc *desc)
 {
     desc->arch.type = DT_IRQ_TYPE_INVALID;
     return 0;
 }
 
+static void init_one_irq_data(int irq, struct irq_desc *desc)
+{
+        init_one_irq_desc(desc);
+        desc->irq = irq;
+        desc->virq = 0;
+        desc->action  = NULL;
+        desc->data = NULL;
+}
 
 static int __init init_irq_data(void)
 {
@@ -72,7 +205,9 @@ static int __init init_irq_data(void)
         struct irq_desc *desc = irq_to_desc(irq);
         init_one_irq_desc(desc);
         desc->irq = irq;
+        desc->virq = 0;
         desc->action  = NULL;
+        desc->data = NULL;
     }
 
     return 0;
@@ -133,6 +268,7 @@ void __init init_IRQ(void)
 
     BUG_ON(init_local_irq_data() < 0);
     BUG_ON(init_irq_data() < 0);
+    radix_tree_init(&desc_root);
 }
 
 void __cpuinit init_secondary_IRQ(void)
@@ -278,11 +414,15 @@ out_no_end:
 void release_irq(unsigned int irq, const void *dev_id)
 {
     struct irq_desc *desc;
+    struct pending_irq *p;
     unsigned long flags;
     struct irqaction *action, **action_ptr;
+    struct vcpu *v = current;
 
     desc = irq_to_desc(irq);
 
+    if ( !desc ) return;
+
     spin_lock_irqsave(&desc->lock,flags);
 
     action_ptr = &desc->action;
@@ -319,6 +459,14 @@ void release_irq(unsigned int irq, const void *dev_id)
 
     if ( action->free_on_release )
         xfree(action);
+
+    if ( is_lpi(irq) )
+    {
+        desc = delete_irq_desc(&desc_root, irq);
+        p = delete_pending_irq_desc(v->domain, irq);
+        xfree(desc);
+        xfree(p);
+    }
 }
 
 static int __setup_irq(struct irq_desc *desc, unsigned int irqflags,
@@ -357,6 +505,8 @@ int setup_irq(unsigned int irq, unsigned int irqflags, struct irqaction *new)
 
     desc = irq_to_desc(irq);
 
+    ASSERT(desc != NULL);
+
     spin_lock_irqsave(&desc->lock, flags);
 
     if ( test_bit(_IRQ_GUEST, &desc->status) )
@@ -400,7 +550,8 @@ int route_irq_to_guest(struct domain *d, unsigned int irq,
                        const char * devname)
 {
     struct irqaction *action;
-    struct irq_desc *desc = irq_to_desc(irq);
+    struct irq_desc *desc;
+    struct pending_irq *p;
     unsigned long flags;
     int retval = 0;
 
@@ -412,6 +563,20 @@ int route_irq_to_guest(struct domain *d, unsigned int irq,
     action->name = devname;
     action->free_on_release = 1;
 
+    if ( is_lpi(irq) )
+    {
+        desc = insert_irq_desc(&desc_root, irq);
+        if ( !desc )
+            return -ENOMEM;
+        init_one_irq_data(irq, desc);
+
+        p = insert_pending_irq_desc(d, irq);
+        if ( !p )
+            return -ENOMEM;
+    }
+    else
+        desc = irq_to_desc(irq);
+
     spin_lock_irqsave(&desc->lock, flags);
 
     /* If the IRQ is already used by someone
@@ -550,6 +715,7 @@ int platform_get_irq(const struct dt_device_node *device, int index)
 {
     struct dt_irq dt_irq;
     unsigned int type, irq;
+    struct irq_desc *desc;
     int res;
 
     res = dt_device_get_irq(device, index, &dt_irq);
@@ -559,6 +725,17 @@ int platform_get_irq(const struct dt_device_node *device, int index)
     irq = dt_irq.irq;
     type = dt_irq.type;
 
+    if ( is_lpi(irq) )
+    {
+        desc = insert_irq_desc(&desc_root, irq);
+        if ( !desc )
+            return -ENOMEM;
+        init_one_irq_data(irq, desc);
+        /* XXX: Here we don't know which is the domain.
+         * So pending irq structure is allocate when required
+         */
+    }
+
     /* Setup the IRQ type */
     if ( irq < NR_LOCAL_IRQS )
         res = irq_local_set_type(irq, type);
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index b272d86..3bf9ef3 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -30,6 +30,7 @@
 
 #include <asm/mmio.h>
 #include <asm/gic.h>
+#include <asm/gic-its.h>
 #include <asm/vgic.h>
 
 static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, int rank)
@@ -108,6 +109,9 @@ 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);
 
+    radix_tree_init(&d->arch.vgic.pending_lpis);
+    spin_lock_init(&d->arch.vgic.pending_lpi_lock);
+
     d->arch.vgic.handler->domain_init(d);
 
     return 0;
@@ -118,10 +122,17 @@ void register_vgic_ops(struct domain *d, const struct vgic_ops *ops)
    d->arch.vgic.handler = ops;
 }
 
+void free_pending_lpis(void *ptr)
+{
+   struct pending_irq *pending_desc = ptr;
+   xfree(pending_desc);
+}
+
 void domain_vgic_free(struct domain *d)
 {
     xfree(d->arch.vgic.shared_irqs);
     xfree(d->arch.vgic.pending_irqs);
+    radix_tree_destroy(&d->arch.vgic.pending_lpis, free_pending_lpis);
 }
 
 int vcpu_vgic_init(struct vcpu *v)
@@ -348,13 +359,18 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int
 
 struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
 {
-    struct pending_irq *n;
+    struct pending_irq *n = NULL;
     /* Pending irqs allocation strategy: the first vgic.nr_spis irqs
      * are used for SPIs; the rests are used for per cpu irqs */
     if ( irq < 32 )
         n = &v->arch.vgic.pending_irqs[irq];
-    else
+    else if ( irq < 1024 )
         n = &v->domain->arch.vgic.pending_irqs[irq - 32];
+    else
+    {
+        if ( is_lpi(irq) )
+            n = find_pending_irq_desc(v->domain, irq);
+    }
     return n;
 }
 
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index b6d85b8..715eb7e 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -11,6 +11,7 @@
 #include <asm/gic.h>
 #include <public/hvm/params.h>
 #include <xen/serial.h>
+#include <xen/radix-tree.h>
 #include <xen/hvm/iommu.h>
 
 struct hvm_domain
@@ -96,6 +97,9 @@ struct arch_domain
          * struct arch_vcpu.
          */
         struct pending_irq *pending_irqs;
+        /* Lock for managing pending lpi in radix tree */
+        spinlock_t pending_lpi_lock;
+        struct radix_tree_root pending_lpis;
         /* Base address for guest GIC */
         paddr_t dbase; /* Distributor base address */
         paddr_t cbase; /* CPU base address */
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index eac738f..6f2237f 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -167,6 +167,8 @@
 
 #define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE(DT_COMPAT_GIC_V3)
 
+#define is_lpi(lpi) ((lpi) >= 8192)
+
 /*
  * GICv3 registers that needs to be saved/restored
  */
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index de029e4..1159a6d 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -2,6 +2,7 @@
 #define _ASM_HW_IRQ_H
 
 #include <xen/config.h>
+#include <xen/radix-tree.h>
 #include <xen/device_tree.h>
 
 #define NR_VECTORS 256 /* XXX */
@@ -27,6 +28,7 @@ struct arch_irq_desc {
 #define arch_hwdom_irqs(domid) NR_IRQS
 
 struct irq_desc;
+struct pending_irq;
 struct irqaction;
 
 struct irq_desc *__irq_to_desc(int irq);
@@ -52,6 +54,14 @@ int platform_get_irq(const struct dt_device_node *device, int index);
 
 void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
 
+struct irq_desc *find_irq_desc(struct radix_tree_root *root_node, int irq);
+struct irq_desc *insert_irq_desc(struct radix_tree_root *root_node, int irq);
+struct irq_desc *delete_irq_desc(struct radix_tree_root *root_node, int irq);
+
+struct pending_irq *insert_pending_irq_desc(struct domain *d, int irq);
+struct pending_irq *find_pending_irq_desc(struct domain *d, int irq);
+struct pending_irq *delete_pending_irq_desc(struct domain *d, int irq);
+
 #endif /* _ASM_HW_IRQ_H */
 /*
  * Local variables:
-- 
1.7.9.5

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

* [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (15 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 16/19] xen/arm: its: Dynamic allocation of LPI descriptors vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-03 18:07   ` Stefano Stabellini
  2015-03-02 12:30 ` [RFC PATCH 18/19] xen/arm: its: Generate ITS node for Dom0 vijay.kilari
                   ` (3 subsequent siblings)
  20 siblings, 1 reply; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Add support for handling ITS(LPI) interrupts.
The LPI interrupts are handled by physical ITS
driver.

nested LPI interrupt handling is not tested and
enabled.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c  |   31 +++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c      |    8 ++++++--
 xen/arch/arm/gic.c         |   38 ++++++++++++++++++++++++++++++++++++--
 xen/arch/arm/irq.c         |   10 +++++++---
 xen/arch/arm/vgic-v3-its.c |   10 ++++++++++
 xen/arch/arm/vgic.c        |   14 ++++++++++----
 xen/include/asm-arm/gic.h  |    3 +++
 xen/include/asm-arm/irq.h  |    1 +
 8 files changed, 104 insertions(+), 11 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index b2c3320..7adbee4 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -344,6 +344,37 @@ static const struct gic_its_hw_operations gic_its_ops = {
     .gic_guest_lpi_type  = &gic_guest_its_type,
 };
 
+void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs)
+{
+    struct domain *d;
+    struct irq_desc *desc = irq_to_desc(irqnr);
+
+    irq_enter();
+    spin_lock(&desc->lock);
+
+    if ( !desc->action )
+    {
+        printk("UNKNOWN LPI without handler\n");
+        goto err;
+    }
+
+    if ( desc->status & IRQ_GUEST )
+    {
+        d = irq_get_domain(desc);
+
+        desc->handler->end(desc);
+
+        desc->status |= IRQ_INPROGRESS;
+        desc->arch.eoi_cpu = smp_processor_id();
+
+        /* XXX: inject irq into all guest vcpus */
+        vgic_vcpu_inject_irq(d->vcpu[0], irqnr);
+    }
+err:
+    spin_unlock(&desc->lock);
+    irq_exit();
+}
+
 static u64 its_cmd_ptr_to_offset(struct its_node *its,
                                  struct its_cmd_block *ptr)
 {
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 02e71dd..b654535 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -848,9 +848,13 @@ static void gicv3_update_lr(int lr, const struct pending_irq *p,
 
     val =  (((uint64_t)state & 0x3) << GICH_LR_STATE_SHIFT) | grp;
     val |= ((uint64_t)p->priority & 0xff) << GICH_LR_PRIORITY_SHIFT;
-    val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;
 
-   if ( p->desc != NULL )
+    if ( is_lpi(p->irq) )
+        val |= ((uint64_t)p->desc->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;
+    else
+        val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;
+
+   if ( p->desc != NULL && !(is_lpi(p->irq)) )
        val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK)
                            << GICH_LR_PHYSICAL_SHIFT);
 
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index fb77387..c4d352a 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -34,6 +34,7 @@
 #include <asm/io.h>
 #include <asm/gic.h>
 #include <asm/vgic.h>
+#include <asm/gic-its.h>
 
 static void gic_restore_pending_irqs(struct vcpu *v);
 
@@ -134,6 +135,21 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
     gic_set_irq_properties(desc, cpu_mask, priority);
 }
 
+void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
+                            const cpumask_t *cpu_mask, unsigned int priority)
+{
+    struct pending_irq *p;
+    ASSERT(spin_is_locked(&desc->lock));
+
+    desc->handler = gic_its_hw_ops->gic_guest_lpi_type;
+    set_bit(_IRQ_GUEST, &desc->status);
+
+     
+    /* TODO: do not assume delivery to vcpu0 */
+    p = irq_to_pending(d->vcpu[0], desc->irq);
+    p->desc = desc;
+}
+
 /* Program the GIC to route an interrupt to a guest
  *   - desc.lock must be held
  */
@@ -341,20 +357,33 @@ static void gic_update_one_lr(struct vcpu *v, int i)
     struct pending_irq *p;
     int irq;
     struct gic_lr lr_val;
+    uint32_t pirq;
 
     ASSERT(spin_is_locked(&v->arch.vgic.lock));
     ASSERT(!local_irq_is_enabled());
 
     gic_hw_ops->read_lr(i, &lr_val);
     irq = lr_val.virq;
-    p = irq_to_pending(v, irq);
+
+    if ( is_lpi(irq) )
+    {
+        // Fetch corresponding plpi for vlpi
+        if ( vgic_its_get_pid(v, irq, &pirq) )
+            BUG();
+        p = irq_to_pending(v, pirq);
+        irq = pirq;
+    }
+    else
+    {
+        p = irq_to_pending(v, irq);
+    }
     if ( lr_val.state & GICH_LR_ACTIVE )
     {
         set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
         if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) &&
              test_and_clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status) )
         {
-            if ( p->desc == NULL )
+            if ( p->desc == NULL  || is_lpi(irq) )
             {
                  lr_val.state |= GICH_LR_PENDING;
                  gic_hw_ops->write_lr(i, &lr_val);
@@ -580,6 +609,11 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
     do  {
         /* Reading IRQ will ACK it */
         irq = gic_hw_ops->read_irq();
+        if ( is_lpi(irq) ) {
+            // TODO: Enable irqs?
+            its_handle_lpi(irq, regs);
+            continue;
+        }
 
         if ( likely(irq >= 16 && irq < 1021) )
         {
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 13583b4..52371be 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -276,7 +276,7 @@ void __cpuinit init_secondary_IRQ(void)
     BUG_ON(init_local_irq_data() < 0);
 }
 
-static inline struct domain *irq_get_domain(struct irq_desc *desc)
+struct domain *irq_get_domain(struct irq_desc *desc)
 {
     ASSERT(spin_is_locked(&desc->lock));
 
@@ -603,9 +603,13 @@ int route_irq_to_guest(struct domain *d, unsigned int irq,
     retval = __setup_irq(desc, 0, action);
     if ( retval )
         goto out;
+    if ( irq >= NR_LOCAL_IRQS && irq < NR_IRQS)
+        gic_route_irq_to_guest(d, desc, cpumask_of(smp_processor_id()),
+                               GIC_PRI_IRQ);
+    else
+        gic_route_lpi_to_guest(d, desc, cpumask_of(smp_processor_id()),
+                               GIC_PRI_IRQ);
 
-    gic_route_irq_to_guest(d, desc, cpumask_of(smp_processor_id()),
-                           GIC_PRI_IRQ);
     spin_unlock_irqrestore(&desc->lock, flags);
     return 0;
 
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index e7e587e..51b9614 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -1022,6 +1022,16 @@ int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid)
     return 1;
 }
 
+uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid)
+{
+    uint8_t priority;
+  
+    priority =  readb_relaxed(v->domain->arch.vits->lpi_prop_page + pid);
+    priority &= 0xfc;
+
+    return priority;
+}
+
 static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
 {
     uint32_t offset;
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 3bf9ef3..5571856 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -389,14 +389,20 @@ void vgic_clear_pending_irqs(struct vcpu *v)
 void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq)
 {
     uint8_t priority;
-    struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);
+    struct vgic_irq_rank *rank;
     struct pending_irq *iter, *n = irq_to_pending(v, irq);
     unsigned long flags;
     bool_t running;
 
-    vgic_lock_rank(v, rank, flags);
-    priority = v->domain->arch.vgic.handler->get_irq_priority(v, irq);
-    vgic_unlock_rank(v, rank, flags);
+    if ( irq < NR_GIC_LPI )
+    {
+        rank = vgic_rank_irq(v, irq);
+        vgic_lock_rank(v, rank, flags);
+        priority = v->domain->arch.vgic.handler->get_irq_priority(v, irq);
+        vgic_unlock_rank(v, rank, flags);
+    }
+    else
+        priority = vgic_its_get_priority(v, irq);
 
     spin_lock_irqsave(&v->arch.vgic.lock, flags);
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 6f2237f..075f488 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -220,6 +220,7 @@ enum gic_version {
 
 extern enum gic_version gic_hw_version(void);
 extern void gic_eoi_irq(struct irq_desc *desc);
+extern void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs);
 /* Program the GIC to route an interrupt */
 extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
                                  unsigned int priority);
@@ -356,6 +357,8 @@ void register_gic_ops(const struct gic_hw_operations *ops);
 void register_gic_its_ops(const struct gic_its_hw_operations *ops);
 int gic_make_node(const struct domain *d,const struct dt_device_node *node,
                   void *fdt);
+void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
+                            const cpumask_t *cpu_mask, unsigned int priority);
 
 #endif /* __ASSEMBLY__ */
 #endif
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 1159a6d..19246f9 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -51,6 +51,7 @@ int irq_set_spi_type(unsigned int spi, unsigned int type);
 int irq_set_desc_data(unsigned int irq, void *d);
 void *irq_get_desc_data(struct irq_desc *d);
 int platform_get_irq(const struct dt_device_node *device, int index);
+struct domain *irq_get_domain(struct irq_desc *desc);
 
 void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
 
-- 
1.7.9.5

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

* [RFC PATCH 18/19] xen/arm: its: Generate ITS node for Dom0
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (16 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 12:30 ` [RFC PATCH 19/19] xen/arm: its: Initialize virtual and physical ITS driver vijay.kilari
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Parse host dt and generate ITS node for Dom0.
ITS node resides inside GIC node so when GIC node
is encountered look for ITS node.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/domain_build.c   |   59 ++++++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/gic-v3-its.c     |   46 ++++++++++++++++++++++++++++++++
 xen/common/device_tree.c      |    2 ++
 xen/include/asm-arm/gic-its.h |    2 ++
 xen/include/asm-arm/gic.h     |    2 ++
 xen/include/xen/device_tree.h |    1 +
 6 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 0be639b..9960d25 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -20,6 +20,7 @@
 #include <asm/cpufeature.h>
 
 #include <asm/gic.h>
+#include <asm/gic-its.h>
 #include <xen/irq.h>
 #include "kernel.h"
 
@@ -785,6 +786,45 @@ static int make_cpus_node(const struct domain *d, void *fdt,
     return res;
 }
 
+static int make_its_node(const struct domain *d, void *fdt,
+                         const struct dt_device_node *node)
+{
+    const struct dt_device_node *its = dt_msi_controller;
+    int res = 0;
+
+    /*
+     * Xen currently supports only a single GIC. Discard any secondary
+     * GIC entries.
+     */
+    if ( node != dt_msi_controller )
+    {
+        DPRINT("  Skipping Secondary ITS\n");
+        return 0;
+    }
+
+    DPRINT("Create GIC ITS node\n");
+
+    res = its_make_dt_node(d, node, fdt);
+    if ( res )
+        return res;
+
+    /*
+     * The value of the property "phandle" in the property "interrupts"
+     * to know on which interrupt controller the interrupt is wired.
+     */
+    if ( its->phandle )
+    {
+        DPRINT("  Set phandle = 0x%x\n", its->phandle);
+        res = fdt_property_cell(fdt, "phandle", its->phandle);
+        if ( res )
+            return res;
+    }
+
+    res = fdt_end_node(fdt);
+
+    return res;
+}
+
 static int make_gic_node(const struct domain *d, void *fdt,
                          const struct dt_device_node *node)
 {
@@ -1042,12 +1082,18 @@ static int handle_node(struct domain *d, struct kernel_info *kinfo,
         DT_MATCH_GIC_V3,
         { /* sentinel */ },
     };
+    static const struct dt_device_match gits_matches[] __initconst =
+    {
+        DT_MATCH_GIC_ITS,
+        { /* sentinel */ },
+    };
     static const struct dt_device_match timer_matches[] __initconst =
     {
         DT_MATCH_TIMER,
         { /* sentinel */ },
     };
     struct dt_device_node *child;
+    struct dt_device_node *gic_child;
     int res;
     const char *name;
     const char *path;
@@ -1071,7 +1117,18 @@ static int handle_node(struct domain *d, struct kernel_info *kinfo,
     /* Replace these nodes with our own. Note that the original may be
      * used_by DOMID_XEN so this check comes first. */
     if ( dt_match_node(gic_matches, node) )
-        return make_gic_node(d, kinfo->fdt, node);
+    {
+        if ( !make_gic_node(d, kinfo->fdt, node) )
+        {
+            gic_child = node->child;
+            if ( gic_child != NULL )
+            {
+                if ( dt_match_node(gits_matches, gic_child) )
+                    return make_its_node(d, kinfo->fdt, gic_child);
+            }
+        }
+        return 0;
+    }
     if ( dt_match_node(timer_matches, node) )
         return make_timer_node(d, kinfo->fdt, node);
 
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 7adbee4..dbfda30 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -857,6 +857,49 @@ static void its_cpu_init_collection(void)
     spin_unlock(&its_lock);
 }
 
+int its_make_dt_node(const struct domain *d,
+                     const struct dt_device_node *node, void *fdt)
+{
+    const struct dt_device_node *gic = dt_msi_controller;
+    const void *compatible = NULL;
+    uint32_t len;
+    __be32 *new_cells, *tmp;
+    int res = 0;
+
+    compatible = dt_get_property(gic, "compatible", &len);
+    if ( !compatible )
+    {
+        dprintk(XENLOG_ERR, "Can't find compatible property for the gic node\n");
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    res = fdt_begin_node(fdt, "gic-its");
+    if ( res )
+        return res;
+
+    res = fdt_property(fdt, "compatible", compatible, len);
+    if ( res )
+        return res;
+
+    res = fdt_property(fdt, "msi-controller", NULL, 0);
+    if ( res )
+        return res;
+
+    len = dt_cells_to_size(dt_n_addr_cells(node) + dt_n_size_cells(node));
+
+    new_cells = xzalloc_bytes(len);
+    if ( new_cells == NULL )
+        return -FDT_ERR_XEN(ENOMEM);
+    tmp = new_cells;
+
+    dt_set_range(&tmp, node, d->arch.vits->phys_base, d->arch.vits->phys_size);
+
+    res = fdt_property(fdt, "reg", new_cells, len);
+    xfree(new_cells);
+
+    return res;
+}
+
 static int its_probe(struct dt_device_node *node)
 {
     paddr_t its_addr, its_size;
@@ -886,6 +929,9 @@ static int its_probe(struct dt_device_node *node)
         goto out_unmap;
     }
 
+    /* Set the ITS as the primary MSI controller */
+    dt_msi_controller = node;
+
     its_info("ITS: %s\n", node->full_name);
 
     its = xzalloc(struct its_node);
diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index f72b2e9..e1382c7 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -30,6 +30,8 @@ dt_irq_xlate_func dt_irq_xlate;
 struct dt_device_node *dt_host;
 /* Interrupt controller node*/
 const struct dt_device_node *dt_interrupt_controller;
+/* MSI controller node*/
+const struct dt_device_node *dt_msi_controller;
 
 /**
  * struct dt_alias_prop - Alias property in 'aliases' node
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 5329e9d..0defe6e 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -236,6 +236,8 @@ int its_get_target(uint8_t pcid, uint64_t *pta);
 uint32_t its_get_pta_type(void);
 int its_get_physical_cid(uint32_t *col_id, uint64_t ta);
 int gic_its_send_cmd(struct vcpu *v, struct its_cmd_block *phys_cmd);
+int its_make_dt_node(const struct domain *d,
+                     const struct dt_device_node *node, void *fdt);
 
 #endif /* __ASM_ARM_GIC_ITS_H__ */
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 075f488..efc9ac3 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -156,6 +156,7 @@
 #include <asm-arm/vgic.h>
 
 #define DT_COMPAT_GIC_400            "arm,gic-400"
+#define DT_COMPAT_GIC_ITS            "arm,gic-v3-its"
 #define DT_COMPAT_GIC_CORTEX_A15     "arm,cortex-a15-gic"
 #define DT_COMPAT_GIC_CORTEX_A7      "arm,cortex-a7-gic"
 
@@ -166,6 +167,7 @@
 #define DT_COMPAT_GIC_V3             "arm,gic-v3"
 
 #define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE(DT_COMPAT_GIC_V3)
+#define DT_MATCH_GIC_ITS DT_MATCH_COMPATIBLE(DT_COMPAT_GIC_ITS)
 
 #define is_lpi(lpi) ((lpi) >= 8192)
 
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index 08db8bc..71732ee 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -192,6 +192,7 @@ extern struct dt_device_node *dt_host;
  * TODO: Handle multiple GIC
  */
 extern const struct dt_device_node *dt_interrupt_controller;
+extern const struct dt_device_node *dt_msi_controller;
 
 /**
  * Find the interrupt controller
-- 
1.7.9.5

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

* [RFC PATCH 19/19] xen/arm: its: Initialize virtual and physical ITS driver
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (17 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 18/19] xen/arm: its: Generate ITS node for Dom0 vijay.kilari
@ 2015-03-02 12:30 ` vijay.kilari
  2015-03-02 13:19 ` [RFC PATCH 00/19] xen/arm: Add ITS support Julien Grall
  2015-03-02 14:53 ` Ian Campbell
  20 siblings, 0 replies; 59+ messages in thread
From: vijay.kilari @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, Vijaya Kumar K, manish.jaggi, vijay.kilari

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

Intialize physical ITS driver and virtual ITS driver
based on HW support information available in GICD_TYPER
register.

Based on outcome of lpi_supported() and gic_nr_id_bits()
functions ITS driver is initialized

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-v3-its.c         |   10 ++++++++++
 xen/arch/arm/gic-v3.c             |   21 +++++++++++++++++++++
 xen/arch/arm/gic.c                |   10 ++++++++++
 xen/arch/arm/setup.c              |    1 +
 xen/arch/arm/vgic-v3-its.c        |   28 ++++++++++++++++++++--------
 xen/arch/arm/vgic-v3.c            |    1 +
 xen/include/asm-arm/gic-its.h     |    5 +++++
 xen/include/asm-arm/gic.h         |    8 ++++++++
 xen/include/asm-arm/gic_v3_defs.h |    1 +
 xen/include/asm-arm/vgic.h        |    1 +
 10 files changed, 78 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index dbfda30..b2116d9 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -900,6 +900,16 @@ int its_make_dt_node(const struct domain *d,
     return res;
 }
 
+void its_domain_init(struct domain *d)
+{
+    if ( is_hardware_domain(d) )
+    {
+        d->arch.vits->phys_base = its->phys_base;
+        d->arch.vits->phys_size = its->phys_size;
+    }
+    /* TODO: To implement for domU */
+}
+
 static int its_probe(struct dt_device_node *node)
 {
     paddr_t its_addr, its_size;
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index b654535..67d34a6 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -658,6 +658,11 @@ static int __init gicv3_populate_rdist(void)
     return -ENODEV;
 }
 
+static int gicv3_dist_supports_lpis(void)
+{
+    return readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_LPIS_SUPPORTED;
+}
+
 static int __cpuinit gicv3_cpu_init(void)
 {
     int i;
@@ -670,6 +675,15 @@ static int __cpuinit gicv3_cpu_init(void)
     if ( gicv3_enable_redist() )
         return -ENODEV;
 
+    if ( gicv3_dist_supports_lpis() )
+        gicv3_info.lpi_supported = 1;
+    else
+        gicv3_info.lpi_supported = 0;
+
+        /* Give LPIs a spin */
+    if ( gicv3_info.lpi_supported )
+        its_cpu_init();
+
     /* Set priority on PPI and SGI interrupts */
     priority = (GIC_PRI_IPI << 24 | GIC_PRI_IPI << 16 | GIC_PRI_IPI << 8 |
                 GIC_PRI_IPI);
@@ -1269,10 +1283,17 @@ static int __init gicv3_init(struct dt_device_node *node, const void *data)
            gicv3.rdist_regions[0].size, gicv3.rdist_regions[0].map_base,
            gicv3_info.maintenance_irq);
 
+    reg = readl_relaxed(GICD + GICD_TYPER);
+    gicv3.rdist_data.id_bits = ((reg >> 19) & 0x1f) + 1;
+    gicv3_info.nr_id_bits = gicv3.rdist_data.id_bits;
+
     spin_lock_init(&gicv3.lock);
 
     spin_lock(&gicv3.lock);
 
+    if ( gicv3_info.lpi_supported )
+        its_init(node, &gicv3.rdist_data);
+
     gicv3_dist_init();
     res = gicv3_cpu_init();
     gicv3_hyp_init();
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index c4d352a..dbd906d 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -74,6 +74,16 @@ unsigned int gic_number_lines(void)
     return gic_hw_ops->info->nr_lines;
 }
 
+unsigned int gic_nr_id_bits(void)
+{
+    return gic_hw_ops->info->nr_id_bits;
+}
+
+bool_t gic_lpi_supported(void)
+{
+    return gic_hw_ops->info->lpi_supported;
+}
+
 void gic_eoi_irq(struct irq_desc *d)
 {
     gic_hw_ops->eoi_irq(d);
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 43b626b..8c75e0e 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -762,6 +762,7 @@ void __init start_xen(unsigned long boot_phys_offset,
     init_xen_time();
 
     gic_init();
+    vgic_its_init();
 
     p2m_vmid_allocator_init();
 
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 51b9614..e12111d 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -1544,19 +1544,31 @@ static int vgic_map_translation_space(struct domain *d)
 
 int vgic_its_domain_init(struct domain *d) 
 {
-    d->arch.vits = xzalloc(struct vgic_its);
-    if ( d->arch.vits == NULL )
-        return -ENOMEM;
+    if ( gic_lpi_supported() )
+    {
+        d->arch.vits = xzalloc(struct vgic_its);
+        if ( d->arch.vits == NULL )
+            return -ENOMEM;
+
+        INIT_LIST_HEAD(&d->arch.vits->vits_dev_list);
+        spin_lock_init(&d->arch.vits->lock);
+
+        its_domain_init(d);
 
-    INIT_LIST_HEAD(&d->arch.vits->vits_dev_list);
-    spin_lock_init(&d->arch.vits->lock);
+        register_mmio_handler(d, &vgic_gits_mmio_handler, d->arch.vits->phys_base,
+                              SZ_64K);
 
-    register_mmio_handler(d, &vgic_gits_mmio_handler, d->arch.vits->phys_base,
-                          SZ_64K);
+        return vgic_map_translation_space(d);
+    }
 
-    return vgic_map_translation_space(d);
+    return 0;
 }
 
+void vgic_its_init(void)
+{
+    if ( gic_lpi_supported() )
+        its_lpi_init(gic_nr_id_bits());
+}
 
 /*
  * Local variables:
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 89e6195..fa7b241 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1124,6 +1124,7 @@ static int vgic_v3_domain_init(struct domain *d)
         register_mmio_handler(d, &vgic_rdistr_mmio_handler,
             d->arch.vgic.rbase[i], d->arch.vgic.rbase_size[i]);
 
+    vgic_its_domain_init(d);
     return 0;
 }
 
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 0defe6e..329b8a0 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -22,6 +22,8 @@
 #ifndef __ASM_ARM_GIC_ITS_H__
 #define __ASM_ARM_GIC_ITS_H__
 
+#include <asm/gic_v3_defs.h>
+
 #define IRQ_PER_CHUNK 32
 
 /* ITS device structure */
@@ -238,6 +240,9 @@ int its_get_physical_cid(uint32_t *col_id, uint64_t ta);
 int gic_its_send_cmd(struct vcpu *v, struct its_cmd_block *phys_cmd);
 int its_make_dt_node(const struct domain *d,
                      const struct dt_device_node *node, void *fdt);
+void its_domain_init(struct domain *d);
+int its_cpu_init(void);
+int its_init(struct dt_device_node *node, struct rdist_prop *rdist);
 
 #endif /* __ASM_ARM_GIC_ITS_H__ */
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index efc9ac3..67a7122 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -279,6 +279,10 @@ extern void gic_dump_info(struct vcpu *v);
 
 /* Number of interrupt lines */
 extern unsigned int gic_number_lines(void);
+/* Number of interrupt id bits supported */
+extern unsigned int gic_nr_id_bits(void);
+/* LPI support info */
+bool_t gic_lpi_supported(void);
 
 /* IRQ translation function for the device tree */
 int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
@@ -294,6 +298,10 @@ struct gic_info {
     uint8_t nr_lrs;
     /* Maintenance irq number */
     unsigned int maintenance_irq;
+    /* Number of IRQ ID bits supported */
+    uint32_t nr_id_bits;
+    /* LPIs are support information */
+    bool_t lpi_supported; 
 };
 
 struct gic_its_hw_operations {
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index b81f83f..574a838 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -133,6 +133,7 @@
 #define GICR_TYPER_LAST              (1U << 4)
 #define GICR_TYPER_DISTRIBUTED_IMP   (1U << 3)
 
+#define GICD_TYPER_LPIS_SUPPORTED    (1U << 17)
 #define DEFAULT_PMR_VALUE            0xff
 
 #define GICH_VMCR_EOI                (1 << 9)
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 74d5a4e..e0a6166 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -177,6 +177,7 @@ enum gic_sgi_mode;
 
 #define vgic_num_irqs(d)        ((d)->arch.vgic.nr_spis + 32)
 
+extern void vgic_its_init(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);
-- 
1.7.9.5

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (18 preceding siblings ...)
  2015-03-02 12:30 ` [RFC PATCH 19/19] xen/arm: its: Initialize virtual and physical ITS driver vijay.kilari
@ 2015-03-02 13:19 ` Julien Grall
  2015-03-03  3:55   ` Vijay Kilari
  2015-03-02 14:53 ` Ian Campbell
  20 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-02 13:19 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar, manish.jaggi

Hi Vijay,

On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Add ITS support for arm. Following major features
> are supported
>  - GICv3 ITS support for arm64 platform
>  - Supports only single ITS node

Why only one ITS node supported? I though Cavium was using 2 ITS...

>  - LPI descriptors are allocated on-demand
>  - Only ITS Dom0 is supported

Any plan to support guest?

> Vijaya Kumar K (19):
>   xen/arm: add linked list apis
>   xen/arm: its: Import GICv3 ITS driver from linux
>   xen/arm: its: Port ITS driver to xen

A general comment (I haven't read closely the patches). The GICv3 ITS
taken from Linux is modified so heavily (rename function, move out code,
dropping unused code...) that your assumption in patch #1 [1] is wrong.

At the end of this series it would make impossible to backport patch
from Linux.

Regards,

[1] "This is actual GICv3 ITS driver from Linux. [..] This helps to
import any issues found in Linux"

-- 
Julien Grall

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

* Re: [RFC PATCH 01/19] xen/arm: add linked list apis
  2015-03-02 12:30 ` [RFC PATCH 01/19] xen/arm: add linked list apis vijay.kilari
@ 2015-03-02 13:21   ` Jan Beulich
  0 siblings, 0 replies; 59+ messages in thread
From: Jan Beulich @ 2015-03-02 13:21 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, manish.jaggi,
	julien.grall, tim, xen-devel, stefano.stabellini, Vijaya Kumar K

>>> On 02.03.15 at 13:30, <vijay.kilari@gmail.com> wrote:
> --- a/xen/include/xen/list.h
> +++ b/xen/include/xen/list.h
> @@ -385,6 +385,39 @@ static inline void list_splice_init(struct list_head *list,
>      container_of(ptr, type, member)
>  
>  /**
> + * list_first_entry - get the first element from a list
> + * @ptr:        the list head to take the element from.
> + * @type:       the type of the struct this is embedded in.
> + * @member:     the name of the list_struct within the struct.
> + *
> + * Note, that list is expected to be not empty.
> + */
> +#define list_first_entry(ptr, type, member) \
> +        list_entry((ptr)->next, type, member)
> +
> +/**
> + * list_last_entry - get the last element from a list
> + * @ptr:        the list head to take the element from.
> + * @type:       the type of the struct this is embedded in.
> + * @member:     the name of the list_struct within the struct.
> + *
> + * Note, that list is expected to be not empty.
> + */
> +#define list_last_entry(ptr, type, member) \
> +        list_entry((ptr)->prev, type, member)

Imo a patch like this should at least replace trivially obvious open
coded variants of the newly added accessors, like page_list_first()
and page_list_last() in xen/mm.h. Which then would make obvious
that you should also be adding list_next_entry() and
list_prev_entry().

> +/**
> + * list_first_entry_or_null - get the first element from a list
> + * @ptr:        the list head to take the element from.
> + * @type:       the type of the struct this is embedded in.
> + * @member:     the name of the list_struct within the struct.
> + *
> + * Note that if the list is empty, it returns NULL.
> + */
> +#define list_first_entry_or_null(ptr, type, member) \
> +        (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)

Even if not present in Linux, I think this should be augmented by
list_last_entry_or_null().

Jan

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

* Re: [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support
  2015-03-02 12:30 ` [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support vijay.kilari
@ 2015-03-02 14:17   ` Julien Grall
  2015-03-03 17:54   ` Stefano Stabellini
  1 sibling, 0 replies; 59+ messages in thread
From: Julien Grall @ 2015-03-02 14:17 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar, manish.jaggi

Hi Vijay,

On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
> diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> index cb9c99b..d52ee0c 100644
> --- a/xen/arch/arm/irq.c
> +++ b/xen/arch/arm/irq.c
> @@ -89,6 +89,7 @@ static int __cpuinit init_local_irq_data(void)
>          init_one_irq_desc(desc);
>          desc->irq = irq;
>          desc->action  = NULL;
> +        desc->data = NULL;

Why do you initialize desc->data and not desc->virq?

>  
>          /* PPIs are included in local_irqs, we copy the IRQ type from
>           * local_irqs_type when bringing up local IRQ for this CPU in
> @@ -104,6 +105,23 @@ static int __cpuinit init_local_irq_data(void)
>      return 0;
>  }
>  
> +int irq_set_desc_data(unsigned int irq, void *d)
> +{
> +    unsigned long flags;
> +    struct irq_desc *desc = irq_to_desc(irq);
> +
> +    spin_lock_irqsave(&desc->lock, flags);
> +    desc->data = d;
> +    spin_unlock_irqrestore(&desc->lock, flags);
> +
> +    return 0;
> +}
> +
> +void *irq_get_desc_data(struct irq_desc *d)
> +{
> +    return d->data;
> +}
> +

None of those helper are used within this patch series...

>  void __init init_IRQ(void)
>  {
>      int irq;
> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
> index 435dfcd..de029e4 100644
> --- a/xen/include/asm-arm/irq.h
> +++ b/xen/include/asm-arm/irq.h
> @@ -46,7 +46,8 @@ void arch_move_irqs(struct vcpu *v);
>  
>  /* Set IRQ type for an SPI */
>  int irq_set_spi_type(unsigned int spi, unsigned int type);
> -

There is not much reason to drop this blank line.

> +int irq_set_desc_data(unsigned int irq, void *d);
> +void *irq_get_desc_data(struct irq_desc *d);
>  int platform_get_irq(const struct dt_device_node *device, int index);
>  
>  void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
> diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
> index 9e0155c..f12afac 100644
> --- a/xen/include/xen/irq.h
> +++ b/xen/include/xen/irq.h
> @@ -91,6 +91,8 @@ typedef struct irq_desc {
>      spinlock_t lock;
>      struct arch_irq_desc arch;
>      cpumask_var_t affinity;
> +    void *data;   /* IRQ specific data */
> +    int virq;     /* Used to store vlpi */

irq_desc is a common structure. We should not add new field without a
strong argument.

Currently, neither data and virq seems relevant:
	- the IRQ data is already contained in the irq_action. So why do you
need to introduce a new field?
	- the virq field see https://patches.linaro.org/43012/

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
                   ` (19 preceding siblings ...)
  2015-03-02 13:19 ` [RFC PATCH 00/19] xen/arm: Add ITS support Julien Grall
@ 2015-03-02 14:53 ` Ian Campbell
  2015-03-02 17:39   ` Ian Campbell
  20 siblings, 1 reply; 59+ messages in thread
From: Ian Campbell @ 2015-03-02 14:53 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	tim, xen-devel, stefano.stabellini, manish.jaggi

On Mon, 2015-03-02 at 18:00 +0530, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Add ITS support for arm.

Thanks. I think this is the last major bit of stuff from your current
development tree, is that right?

There's quite a few series out there right now from you guys, with quite
a number of patches in each, so I think we need to prioritise the order
we deal with them.

I am intending to go through them in the following order:
      * Basic platform support code
      * PCI support
      * ITS support
      * Other new work (e.g. NUMA)

Does that ordering suit your plans?

I think we don't want to build up too much of a backlog so it would be
good to put an emphasis on addressing comments & resending stuff nearer
the top of the list first.

(With that in mind I think the basic platform device was almost there
but needed a couple of minor things addressing in one patch).

Cheers,
Ian.

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-02 14:53 ` Ian Campbell
@ 2015-03-02 17:39   ` Ian Campbell
  2015-03-03  4:02     ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Ian Campbell @ 2015-03-02 17:39 UTC (permalink / raw)
  To: vijay.kilari
  Cc: stefano.stabellini, Prasun.Kapoor, vijaya.kumar, julien.grall,
	tim, xen-devel, stefano.stabellini, manish.jaggi

Forgot one series (albeit of a single patch):

On Mon, 2015-03-02 at 14:53 +0000, Ian Campbell wrote:
> There's quite a few series out there right now from you guys, with quite
> a number of patches in each, so I think we need to prioritise the order
> we deal with them.
> 
> I am intending to go through them in the following order:
>       * Basic platform support code

        * VMAP PTE present fix

>       * PCI support
>       * ITS support
>       * Other new work (e.g. NUMA)
> 
> Does that ordering suit your plans?
> 
> I think we don't want to build up too much of a backlog so it would be
> good to put an emphasis on addressing comments & resending stuff nearer
> the top of the list first.
> 
> (With that in mind I think the basic platform device was almost there
> but needed a couple of minor things addressing in one patch).
> 
> Cheers,
> Ian.
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-02 13:19 ` [RFC PATCH 00/19] xen/arm: Add ITS support Julien Grall
@ 2015-03-03  3:55   ` Vijay Kilari
  2015-03-03 11:43     ` Julien Grall
  0 siblings, 1 reply; 59+ messages in thread
From: Vijay Kilari @ 2015-03-03  3:55 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hi Julien,

On Mon, Mar 2, 2015 at 6:49 PM, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Vijay,
>
> On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> Add ITS support for arm. Following major features
>> are supported
>>  - GICv3 ITS support for arm64 platform
>>  - Supports only single ITS node
>
> Why only one ITS node supported? I though Cavium was using 2 ITS...

I will update for 2 ITS nodes later when NUMA is supported

>
>>  - LPI descriptors are allocated on-demand
>>  - Only ITS Dom0 is supported
>
> Any plan to support guest?

Yes, I will do it in next version

>
>> Vijaya Kumar K (19):
>>   xen/arm: add linked list apis
>>   xen/arm: its: Import GICv3 ITS driver from linux
>>   xen/arm: its: Port ITS driver to xen
>
> A general comment (I haven't read closely the patches). The GICv3 ITS
> taken from Linux is modified so heavily (rename function, move out code,
> dropping unused code...) that your assumption in patch #1 [1] is wrong.
>
> At the end of this series it would make impossible to backport patch
> from Linux.

  Most of the code is reused or moved to different file based on Xen
requirement.
    - code like msi registered callback (setup_irq & teardown_irq) is of
no use in Xen. So removed
    - irq_chip is different in linux
    - some of the functions like encode of ITS commands can be used in
virtual ITS
      driver as well. So have to be moved out to header file
    - the LPI allocation is moved to virtual ITS driver. We can
consider it keeping in physical ITS
      driver but it fits well in virtual ITS driver rather than
physical ITS driver.


>
> Regards,
>
> [1] "This is actual GICv3 ITS driver from Linux. [..] This helps to
> import any issues found in Linux"

I have kept the linux GICv3 ITS driver in first patch and made incremental
changes just to have better understanding and incremental approach

Regards
Vijay

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-02 17:39   ` Ian Campbell
@ 2015-03-03  4:02     ` Vijay Kilari
  2015-03-03 10:07       ` Ian Campbell
  0 siblings, 1 reply; 59+ messages in thread
From: Vijay Kilari @ 2015-03-03  4:02 UTC (permalink / raw)
  To: Ian Campbell
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hi Ian,

On Mon, Mar 2, 2015 at 11:09 PM, Ian Campbell <ian.campbell@citrix.com> wrote:
> Forgot one series (albeit of a single patch):
>
> On Mon, 2015-03-02 at 14:53 +0000, Ian Campbell wrote:
>> There's quite a few series out there right now from you guys, with quite
>> a number of patches in each, so I think we need to prioritise the order
>> we deal with them.
>>
>> I am intending to go through them in the following order:
>>       * Basic platform support code
>
>         * VMAP PTE present fix
>
>>       * PCI support
>>       * ITS support
>>       * Other new work (e.g. NUMA)
>>
>> Does that ordering suit your plans?
>>
>> I think we don't want to build up too much of a backlog so it would be
>> good to put an emphasis on addressing comments & resending stuff nearer
>> the top of the list first.
>>
>> (With that in mind I think the basic platform device was almost there
>> but needed a couple of minor things addressing in one patch).

Agreed, But the patch series sent are completely independent.
Holding back patches will delay things. I have sent ITS patch series to
get first feedback. Meanwhile, I will work on platform & VMAP patches

As Manish is working on PCI, Any changes to ITS driver for
PCI stuff will be managed separately.

Regards
Vijay

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-03  4:02     ` Vijay Kilari
@ 2015-03-03 10:07       ` Ian Campbell
  0 siblings, 0 replies; 59+ messages in thread
From: Ian Campbell @ 2015-03-03 10:07 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Tue, 2015-03-03 at 09:32 +0530, Vijay Kilari wrote:
> Hi Ian,
> 
> On Mon, Mar 2, 2015 at 11:09 PM, Ian Campbell <ian.campbell@citrix.com> wrote:
> > Forgot one series (albeit of a single patch):
> >
> > On Mon, 2015-03-02 at 14:53 +0000, Ian Campbell wrote:
> >> There's quite a few series out there right now from you guys, with quite
> >> a number of patches in each, so I think we need to prioritise the order
> >> we deal with them.
> >>
> >> I am intending to go through them in the following order:
> >>       * Basic platform support code
> >
> >         * VMAP PTE present fix
> >
> >>       * PCI support
> >>       * ITS support
> >>       * Other new work (e.g. NUMA)
> >>
> >> Does that ordering suit your plans?
> >>
> >> I think we don't want to build up too much of a backlog so it would be
> >> good to put an emphasis on addressing comments & resending stuff nearer
> >> the top of the list first.
> >>
> >> (With that in mind I think the basic platform device was almost there
> >> but needed a couple of minor things addressing in one patch).
> 
> Agreed, But the patch series sent are completely independent.

True, but maintainer bandwidth for review is not (nor is it infinite).

So I just wanted to set your expectations wrt what order I would be
dealing with things in (along with all the other stuff I have to
review).

> Holding back patches will delay things. I have sent ITS patch series to
> get first feedback. Meanwhile, I will work on platform & VMAP patches
> 
> As Manish is working on PCI, Any changes to ITS driver for
> PCI stuff will be managed separately.
> 
> Regards
> Vijay

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-03  3:55   ` Vijay Kilari
@ 2015-03-03 11:43     ` Julien Grall
  2015-03-09 12:57       ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-03 11:43 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hello Vijay,

On 03/03/2015 03:55, Vijay Kilari wrote:
> On Mon, Mar 2, 2015 at 6:49 PM, Julien Grall <julien.grall@linaro.org> wrote:
>> On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>
>>> Add ITS support for arm. Following major features
>>> are supported
>>>   - GICv3 ITS support for arm64 platform
>>>   - Supports only single ITS node
>>
>> Why only one ITS node supported? I though Cavium was using 2 ITS...
>
> I will update for 2 ITS nodes later when NUMA is supported

Why do you speak about NUMA? AFAICT, there is no requirement to support 
NUMA for having multiple ITS...

With multiple ITS support, your vITS emulation will likely heavily 
change. So it would be nice to have this support as soon as possible.

>>
>>>   - LPI descriptors are allocated on-demand
>>>   - Only ITS Dom0 is supported
>>
>> Any plan to support guest?
>
> Yes, I will do it in next version

What is missing to support guest? Only the toolstack part?

>>
>>> Vijaya Kumar K (19):
>>>    xen/arm: add linked list apis
>>>    xen/arm: its: Import GICv3 ITS driver from linux
>>>    xen/arm: its: Port ITS driver to xen
>>
>> A general comment (I haven't read closely the patches). The GICv3 ITS
>> taken from Linux is modified so heavily (rename function, move out code,
>> dropping unused code...) that your assumption in patch #1 [1] is wrong.
>>
>> At the end of this series it would make impossible to backport patch
>> from Linux.
>
>    Most of the code is reused or moved to different file based on Xen
> requirement.
>      - code like msi registered callback (setup_irq & teardown_irq) is of
> no use in Xen. So removed
>      - irq_chip is different in linux
>      - some of the functions like encode of ITS commands can be used in
> virtual ITS
>        driver as well. So have to be moved out to header file
>      - the LPI allocation is moved to virtual ITS driver. We can
> consider it keeping in physical ITS
>        driver but it fits well in virtual ITS driver rather than
> physical ITS driver.

IHMO, moving the code around two files make the code more difficult to 
review because the patch is bigger.

That also means we can't really review the first couple of patches 
because the code will change a lot after.

But the maintainers may be disagree with me...

>>
>> Regards,
>>
>> [1] "This is actual GICv3 ITS driver from Linux. [..] This helps to
>> import any issues found in Linux"
>
> I have kept the linux GICv3 ITS driver in first patch and made incremental
> changes just to have better understanding and incremental approach

But this is doesn't help to backport issue from Linux...

BTW, do you have a tree with all the code?

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs
  2015-03-02 12:30 ` [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs vijay.kilari
@ 2015-03-03 17:16   ` Stefano Stabellini
  2015-03-04 12:10     ` Stefano Stabellini
  0 siblings, 1 reply; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-03 17:16 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, Vijaya Kumar K,
	julien.grall, tim, xen-devel, stefano.stabellini, manish.jaggi

On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> With this patch add emulation of GICR registers for LPIs.
> Also add LPI property table emulation.
> 
> Domain's LPI property table is unmapped during domain init
> on LPIPROPBASE update and trapped on LPI property
> table read and write
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/vgic-v3-its.c        |  156 +++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic-v3.c            |   64 ++++++++++++---
>  xen/include/asm-arm/domain.h      |    1 +
>  xen/include/asm-arm/gic-its.h     |    1 +
>  xen/include/asm-arm/gic.h         |    2 +
>  xen/include/asm-arm/gic_v3_defs.h |    2 +
>  6 files changed, 214 insertions(+), 12 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
> index 7e1cc04..48c880a 100644
> --- a/xen/arch/arm/vgic-v3-its.c
> +++ b/xen/arch/arm/vgic-v3-its.c
> @@ -996,6 +996,162 @@ err:
>      return 0;
>  }
>  
> +/* Search device structure and get corresponding plpi */
> +int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid)
> +{
> +    struct domain *d = v->domain;
> +    struct vits_device *dev;
> +    struct its_lpi_chunk *chunk;
> +    int i;
> +
> +    list_for_each_entry( dev, &d->arch.vits->vits_dev_list, entry )
> +    {
> +        list_for_each_entry( chunk, &dev->hwirq_list, entry )
> +        {
> +            for ( i = 0; i < IRQS_PER_CHUNK; i++ )
> +            {
> +                if ( test_bit(i, &chunk->lpi_map) && chunk->vid[i] == vid )
> +                {
> +                    *pid = chunk->pid[i];
> +                     return 0;
> +                }
> +            }
> +        }
> +    }
> +
> +    return 1;
> +}
> +
> +static int vgic_v3_gits_lpi_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);
> +    uint8_t cfg;
> +
> +    spin_lock(&v->domain->arch.vits->lock);
> +    offset = info->gpa -
> +             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
> +
> +    if ( offset < SZ_64K )
> +    {
> +        DPRINTK("vITS: LPI Table read offset 0x%x\n", offset );
> +        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
> +        *r = cfg;
> +        spin_unlock(&v->domain->arch.vits->lock);
> +        return 1;
> +    }
> +    else
> +        dprintk(XENLOG_ERR, "vITS: LPI Table read with wrong offset 0x%x\n",
> +                offset);
> +
> +    spin_unlock(&v->domain->arch.vits->lock);
> +
> +    return 0;
> +}
> +
> +static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
> +{
> +    uint32_t offset;
> +    uint32_t pid, vid;
> +    uint8_t cfg;
> +    bool_t enable;
> +    struct hsr_dabt dabt = info->dabt;
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    register_t *r = select_user_reg(regs, dabt.reg);
> +
> +    spin_lock(&v->domain->arch.vits->lock);
> +    offset = info->gpa -
> +             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
> +
> +    vid = offset + NR_GIC_LPI;
> +    if ( offset < SZ_64K )
> +    {
> +        DPRINTK("vITS: LPI Table write offset 0x%x\n", offset );
> +        if ( vgic_its_get_pid(v, vid, &pid) )
> +        {
> +            spin_unlock(&v->domain->arch.vits->lock);
> +            dprintk(XENLOG_ERR, "vITS: pID not found for vid %d\n", vid);
> +            return 0;
> +        }
> +
> +        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
> +        enable = (cfg & *r) & 0x1;
> +
> +        if ( !enable )
> +             vgic_its_enable_lpis(v, pid);
> +        else
> +             vgic_its_disable_lpis(v, pid);
> +
> +        /* Update virtual prop page */
> +        writeb_relaxed((*r & 0xff),
> +                        v->domain->arch.vits->lpi_prop_page + offset);

We need to properly support priorities too.


> +        spin_unlock(&v->domain->arch.vits->lock);
> +        return 1;
> +    }
> +    else
> +        dprintk(XENLOG_ERR, "vITS: LPI Table write with wrong offset 0x%x\n",
> +                offset);
> +
> +    spin_unlock(&v->domain->arch.vits->lock);
> +
> +    return 0;
> +}
> +
> +static const struct mmio_handler_ops vgic_gits_lpi_mmio_handler = {
> +    .read_handler  = vgic_v3_gits_lpi_mmio_read,
> +    .write_handler = vgic_v3_gits_lpi_mmio_write,
> +};
> +
> +int vgic_its_unmap_lpi_prop(struct vcpu *v)
> +{
> +    paddr_t maddr;
> +    uint32_t lpi_size;
> +    int i;
> +
> +    spin_lock(&v->domain->arch.vits->lock);
> +    maddr = v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL;
> +    lpi_size = 1UL << ((v->domain->arch.vits->lpi_propbase & 0x1f) + 1);
> +
> +    DPRINTK("vITS: Unmap guest LPI conf table maddr 0x%lx lpi_size 0x%x\n",
> +             maddr, lpi_size);
> +
> +    if ( lpi_size < SZ_64K )
> +    {
> +        spin_unlock(&v->domain->arch.vits->lock);
> +        dprintk(XENLOG_ERR, "vITS: LPI Prop page < 64K\n");
> +        return 0;
> +    }
> +
> +    /* XXX: As per 4.8.9 each re-distributor shares a common LPI configuration table
> +     * So one set of mmio handlers to manage configuration table is enough
> +     */
> +    for ( i = 0; i < lpi_size / PAGE_SIZE; i++ )
> +        guest_physmap_remove_page(v->domain, paddr_to_pfn(maddr),
> +                                gmfn_to_mfn(v->domain, paddr_to_pfn(maddr)), 0);
> +
> +    /* Register mmio handlers for this region */
> +    register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler,
> +                          maddr, lpi_size);
> +
> +    /* Allocate Virtual LPI Property table */
> +    v->domain->arch.vits->lpi_prop_page =
> +        alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0);

I guess we could reuse the original unmapped guest page instead of allocating a new one?


> +    if ( !v->domain->arch.vits->lpi_prop_page )
> +    {
> +        spin_unlock(&v->domain->arch.vits->lock);
> +        dprintk(XENLOG_ERR, "vITS: Failed to allocate LPI Prop page\n");
> +        return 0;
> +    }
> +
> +    memset(v->domain->arch.vits->lpi_prop_page, 0xa2, lpi_size);
> +    spin_unlock(&v->domain->arch.vits->lock);
> +
> +    return 1;
> +}
> +
>  static int __vgic_v3_its_ctrl_mmio_read(struct vcpu *v, mmio_info_t *info,
>                                          uint32_t gits_reg)
>  {
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index bece189..89e6195 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -32,6 +32,7 @@
>  #include <asm/gic_v3_defs.h>
>  #include <asm/gic.h>
>  #include <asm/vgic.h>
> +#include <asm/gic-its.h>
>  
>  /* GICD_PIDRn register values for ARM implementations */
>  #define GICV3_GICD_PIDR0  0x92
> @@ -94,19 +95,29 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
>      switch ( gicr_reg )
>      {
>      case GICR_CTLR:
> -        /* We have not implemented LPI's, read zero */
> -        goto read_as_zero;
> +        /*
> +         * Enable LPI's for ITS. Direct injection of LPI
> +         * by writing to GICR_{SET,CLR}LPIR are not supported
> +         */

Is this actually a limitation that we can have? Is there a way to
communicate to the guest OS that GICR_{SET,CLR}LPIR are not supported?


> +        if ( dabt.size != DABT_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        *r = v->domain->arch.vgic.gicr_ctlr;
> +        vgic_unlock(v);
> +        return 1;
>      case GICR_IIDR:
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          *r = GICV3_GICR_IIDR_VAL;
>          return 1;
>      case GICR_TYPER:
> -        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> -        /* TBD: Update processor id in [23:8] when ITS support is added */
> +        if ( dabt.size != DABT_WORD && dabt.size != DABT_DOUBLE_WORD )
> +            goto bad_width;
> +        /* XXX: Update processor id in [23:8] if GITS_TYPER: PTA is not set */
>          aff = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 56 |
>                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 |
>                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 |
>                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32);
> +        /* Set LPI support */
> +        aff |= (GICR_TYPER_DISTRIBUTED_IMP | GICR_TYPER_PLPIS);
>          *r = aff;
>          return 1;
>      case GICR_STATUSR:
> @@ -122,10 +133,13 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
>          /* WO. Read as zero */
>          goto read_as_zero_64;
>      case GICR_PROPBASER:
> -        /* LPI's not implemented */
> -        goto read_as_zero_64;
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        /* Remove shareability attribute we don't want dom to flush */
> +        *r = v->domain->arch.vits->lpi_propbase;
> +        return 1;
>      case GICR_PENDBASER:
> -        /* LPI's not implemented */
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        *r = v->domain->arch.vits->lpi_pendbase[v->vcpu_id];
>          goto read_as_zero_64;
>      case GICR_INVLPIR:
>          /* WO. Read as zero */
> @@ -200,8 +214,15 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
>      switch ( gicr_reg )
>      {
>      case GICR_CTLR:
> -        /* LPI's not implemented */
> -        goto write_ignore;
> +        /*
> +         * Enable LPI's for ITS. Direct injection of LPI
> +         * by writing to GICR_{SET,CLR}LPIR are not supported
> +         */
> +        if ( dabt.size != DABT_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        v->domain->arch.vgic.gicr_ctlr = (*r) & GICR_CTL_ENABLE;
> +        vgic_unlock(v);
> +        return 1;
>      case GICR_IIDR:
>          /* RO */
>          goto write_ignore;
> @@ -221,11 +242,29 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
>          /* LPI is not implemented */
>          goto write_ignore_64;
>      case GICR_PROPBASER:
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        /* LPI configuration tables are shared across cpus. Should be same */
> +        if ( (v->domain->arch.vits->lpi_propbase != 0) &&
> +             ((v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL) !=  (*r & 0xfffffffff000UL)) )
> +        {
> +            dprintk(XENLOG_G_ERR,
> +                "vGICv3: vITS: Wrong configuration of LPI_PROPBASER\n");
> +            vgic_unlock(v);
> +            return 0;
> +        }
> +        v->domain->arch.vits->lpi_propbase = *r;
> +        vgic_unlock(v);
> +        return vgic_its_unmap_lpi_prop(v);
>          /* LPI is not implemented */
>          goto write_ignore_64;
>      case GICR_PENDBASER:
> -        /* LPI is not implemented */
> -        goto write_ignore_64;
> +        /* Just hold pendbaser value for guest read */
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        v->domain->arch.vits->lpi_pendbase[v->vcpu_id] = *r;
> +        vgic_unlock(v);

If I am not mistaken, nothing updates the virtual LPI pending table with
the status of inflight virtual LPIs.  The pending table is not emulated
at all. I think that at the very least you should add a comment saying
that reading the pending status of LPIs via the pending table is not
supported.


> +        return 1;
>      case GICR_INVLPIR:
>          /* LPI is not implemented */
>          goto write_ignore_64;
> @@ -682,7 +721,8 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          /* No secure world support for guests. */
>          *r = (((v->domain->max_vcpus << 5) & GICD_TYPE_CPUS ) |
> -              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES));
> +              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES) |
> +              GICD_TYPE_LPIS | GICD_TYPE_ID_BITS);
>          return 1;
>      case GICD_STATUSR:
>          /*
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index d02c200..b6d85b8 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -101,6 +101,7 @@ struct arch_domain
>          paddr_t cbase; /* CPU base address */
>  #ifdef CONFIG_ARM_64
>          /* GIC V3 addressing */
> +        int gicr_ctlr;
>          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 */
> diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
> index bb9ac33..5329e9d 100644
> --- a/xen/include/asm-arm/gic-its.h
> +++ b/xen/include/asm-arm/gic-its.h
> @@ -228,6 +228,7 @@ static inline void its_fixup_cmd(struct its_cmd_block *cmd)
>  void vgic_its_enable_lpis(struct vcpu *v, uint32_t lpi);
>  int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid);
>  int vgic_its_domain_init(struct domain *d);
> +int vgic_its_unmap_lpi_prop(struct vcpu *v);
>  uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
>  
>  int its_check_target(uint64_t vta);
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 1b4b7d1..681d75c 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -96,6 +96,8 @@
>  #define GICD_TYPE_LINES 0x01f
>  #define GICD_TYPE_CPUS  0x0e0
>  #define GICD_TYPE_SEC   0x400
> +#define GICD_TYPE_LPIS           (0x1UL << 17)
> +#define GICD_TYPE_ID_BITS        (0x13UL << 19)
>  
>  #define GICC_CTL_ENABLE 0x1
>  #define GICC_CTL_EOI    (0x1 << 9)
> diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
> index 83d75cf..b81f83f 100644
> --- a/xen/include/asm-arm/gic_v3_defs.h
> +++ b/xen/include/asm-arm/gic_v3_defs.h
> @@ -127,9 +127,11 @@
>  #define GICR_PROPBASER_RaWaWb		(7U << 7)
>  #define GICR_PROPBASER_IDBITS_MASK	(0x1f)
>  
> +#define GICR_CTL_ENABLE              (1U << 0)
>  #define GICR_TYPER_PLPIS             (1U << 0)
>  #define GICR_TYPER_VLPIS             (1U << 1)
>  #define GICR_TYPER_LAST              (1U << 4)
> +#define GICR_TYPER_DISTRIBUTED_IMP   (1U << 3)
>  
>  #define DEFAULT_PMR_VALUE            0xff
>  
> -- 
> 1.7.9.5
> 

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

* Re: [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller for LPIs
  2015-03-02 12:30 ` [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller " vijay.kilari
@ 2015-03-03 17:28   ` Stefano Stabellini
  2015-03-09 13:03     ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-03 17:28 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, Vijaya Kumar K,
	julien.grall, tim, xen-devel, stefano.stabellini, manish.jaggi

On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> This patch implements hw_irq_controller api's required
> to handle LPI's.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/gic-v3-its.c |  104 ++++++++++++++++++++++++++++++++++++++++++++-
>  xen/arch/arm/gic.c        |   11 +++++
>  xen/include/asm-arm/gic.h |    8 +++-
>  3 files changed, 121 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
> index 5d9550f..b2c3320 100644
> --- a/xen/arch/arm/gic-v3-its.c
> +++ b/xen/arch/arm/gic-v3-its.c
> @@ -140,6 +140,9 @@ struct its_cmd_desc {
>  typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
>                                  struct its_cmd_desc *);
>  
> +static void its_send_movi(struct its_node *its, struct its_collection *col,
> +                          u32 dev_id, u32 id);
> +
>  uint32_t its_get_pta_type(void)
>  {
>      return pta_type;
> @@ -244,6 +247,103 @@ int its_get_physical_cid(uint32_t *col_id, uint64_t vta)
>      return 1;
>  }
>  
> +static void lpi_set_config(u32 hwirq, u32 id, int enable)
> +{
> +    u8 *cfg;
> +
> +    cfg = gic_rdists->prop_page + hwirq - NR_GIC_LPI;
> +
> +    if ( enable )
> +        *cfg |= (1 << 0);
> +    else
> +        *cfg &= ~(1 << 0);
> +
> +    /*
> +     * Make the above write visible to the redistributors.
> +     * And yes, we're flushing exactly: One. Single. Byte.
> +     * Humpf...
> +     */
> +    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
> +        clean_dcache_va_range(cfg, sizeof(*cfg));
> +    else
> +        dsb(ishst);
> +}
> +
> +static void its_mask_irq(struct irq_desc *d)
> +{
> +    u32 id;
> +
> +    id = d->irq;
> +    set_bit(_IRQ_DISABLED, &d->status);
> +    lpi_set_config(d->irq, id, 0);
> +}
> +
> +static void its_unmask_irq(struct irq_desc *d)
> +{
> +    u32 id;
> +
> +    id = d->irq;
> +    clear_bit(_IRQ_DISABLED, &d->status);
> +    lpi_set_config(d->irq, id, 1);
> +}
> +
> +static unsigned int its_irq_startup(struct irq_desc *desc)
> +{
> +    its_unmask_irq(desc);
> +
> +    return 0;
> +}
> +
> +static void its_irq_shutdown(struct irq_desc *desc)
> +{
> +    its_mask_irq(desc);
> +}
> +
> +static void its_eoi_irq(struct irq_desc *d)
> +{
> +    gic_eoi_irq(d);
> +}
> +
> +static void its_ack_irq(struct irq_desc *desc)
> +{
> +    /* No ACK -- reading IAR has done this for us */
> +}
> +
> +static void its_set_affinity(struct irq_desc *d, const cpumask_t *mask_val)
> +{
> +    /* XXX: check cpumask_any or cpu_online_map is ok? */
> +    cpumask_t online_mask;
> +    unsigned int cpu;
> +    struct vits_device *its_dev = irq_get_desc_data(d);
> +    struct its_collection *target_col;
> +    uint32_t id;
> +
> +    cpumask_and(&online_mask, mask_val, &cpu_online_map);
> +    cpu = cpumask_any(&online_mask);
> +    /* Physical collection id */
> +    target_col = &its->collections[cpu];
> +    /* Physical irq is considered not virq */
> +    id = d->irq;
> +
> +    its_send_movi(its, target_col, its_dev->dev_id, id);
> +}
> +
> +/* TODO: To implement set_affinity */
> +static const hw_irq_controller gic_guest_its_type = {
> +    .typename     = "gic-its",
> +    .startup      = its_irq_startup,
> +    .shutdown     = its_irq_shutdown,
> +    .enable       = its_unmask_irq,
> +    .disable      = its_mask_irq,
> +    .ack          = its_ack_irq,
> +    .end          = its_eoi_irq,
> +    .set_affinity = its_set_affinity,
> +};
> +
> +static const struct gic_its_hw_operations gic_its_ops = {
> +    .gic_guest_lpi_type  = &gic_guest_its_type,
> +};

Aside from the one call to its_send_movi, nothing here is ITS specific.
In fact I would just move all this to gic-v3.c as it feels like part of
the GICv3 driver rather than the ITS driver.


>  static u64 its_cmd_ptr_to_offset(struct its_node *its,
>                                   struct its_cmd_block *ptr)
>  {
> @@ -392,7 +492,7 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col,
>      its_send_single_command(its, its_build_mapc_cmd, &desc);
>  }
>  
> -void its_send_movi(struct its_node *its, struct its_collection *col,
> +static void its_send_movi(struct its_node *its, struct its_collection *col,
>                     u32 dev_id, u32 id)
>  {
>      struct its_cmd_desc desc;
> @@ -872,6 +972,8 @@ int its_init(struct dt_device_node *node, struct rdist_prop *rdists)
>  
>      its_alloc_lpi_tables();
>  
> +    register_gic_its_ops(&gic_its_ops);
> +
>      return 0;
>  }
>  
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 390c8b0..fb77387 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -46,12 +46,18 @@ static DEFINE_PER_CPU(uint64_t, lr_mask);
>  static void gic_update_one_lr(struct vcpu *v, int i);
>  
>  static const struct gic_hw_operations *gic_hw_ops;
> +static const struct gic_its_hw_operations *gic_its_hw_ops;
>  
>  void register_gic_ops(const struct gic_hw_operations *ops)
>  {
>      gic_hw_ops = ops;
>  }
>  
> +void register_gic_its_ops(const struct gic_its_hw_operations *ops)
> +{
> +    gic_its_hw_ops = ops;
> +}

Not clear why you need this.


>  static void clear_cpu_lr_mask(void)
>  {
>      this_cpu(lr_mask) = 0ULL;
> @@ -67,6 +73,11 @@ unsigned int gic_number_lines(void)
>      return gic_hw_ops->info->nr_lines;
>  }
>  
> +void gic_eoi_irq(struct irq_desc *d)
> +{
> +    gic_hw_ops->eoi_irq(d);
> +}
> +
>  void gic_save_state(struct vcpu *v)
>  {
>      ASSERT(!local_irq_is_enabled());
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 681d75c..eac738f 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -217,7 +217,7 @@ enum gic_version {
>  };
>  
>  extern enum gic_version gic_hw_version(void);
> -
> +extern void gic_eoi_irq(struct irq_desc *desc);
>  /* Program the GIC to route an interrupt */
>  extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
>                                   unsigned int priority);
> @@ -291,6 +291,11 @@ struct gic_info {
>      unsigned int maintenance_irq;
>  };
>  
> +struct gic_its_hw_operations {
> +    /* LPI hw_irq_controller to enable/disable/eoi host irq */
> +    hw_irq_controller *gic_guest_lpi_type;
> +};
> +
>  struct gic_hw_operations {
>      /* Hold GIC HW information */
>      const struct gic_info *info;
> @@ -346,6 +351,7 @@ struct gic_hw_operations {
>  };
>  
>  void register_gic_ops(const struct gic_hw_operations *ops);
> +void register_gic_its_ops(const struct gic_its_hw_operations *ops);
>  int gic_make_node(const struct domain *d,const struct dt_device_node *node,
>                    void *fdt);
>  
> -- 
> 1.7.9.5
> 

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

* Re: [RFC PATCH 14/19] xen/arm: vits: Map ITS translation space
  2015-03-02 12:30 ` [RFC PATCH 14/19] xen/arm: vits: Map ITS translation space vijay.kilari
@ 2015-03-03 17:31   ` Stefano Stabellini
  2015-03-03 17:41     ` Julien Grall
  0 siblings, 1 reply; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-03 17:31 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, Vijaya Kumar K,
	julien.grall, tim, xen-devel, stefano.stabellini, manish.jaggi

On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> ITS translation space contains GITS_TRANSLATOR
> register which is written by device to raise
> LPI. This space needs to mapped to every domain
> address space so that device can access GITS_TRANSLATOR
> register using SMMU
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/vgic-v3-its.c |   33 +++++++++++++++++++++++++++++++--
>  1 file changed, 31 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
> index 48c880a..e7e587e 100644
> --- a/xen/arch/arm/vgic-v3-its.c
> +++ b/xen/arch/arm/vgic-v3-its.c
> @@ -1504,7 +1504,35 @@ static const struct mmio_handler_ops vgic_gits_mmio_handler = {
>      .write_handler = vgic_v3_gits_mmio_write,
>  };
>  
> -int vgic_its_domain_init(struct domain *d)
> +/*
> + * Map the 64K ITS translation space in guest.
> + * This is required purely for device smmu writes.
> + */
> +
> +static int vgic_map_translation_space(struct domain *d)
> +{
> +    u64 addr, size;
> +    int ret;
> +    addr = d->arch.vits->phys_base + SZ_64K;
> +    size = SZ_64K;
> +
> +    ret = map_mmio_regions(d,
> +                           paddr_to_pfn(addr & PAGE_MASK),
> +                           DIV_ROUND_UP(size, PAGE_SIZE),
> +                           paddr_to_pfn(addr & PAGE_MASK));
> +
> +     if ( ret )
> +     {
> +          printk(XENLOG_ERR "Unable to map to dom%d access to"
> +                 " 0x%"PRIx64" - 0x%"PRIx64"\n",
> +                 d->domain_id,
> +                 addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1);
> +     }
> +
> +    return ret;
> +}

Although we might want to map it 1:1 anyway, I think that this function
should be able to cope with a virtual GITS_TRANSLATOR address different
from the physical translator address.


> +int vgic_its_domain_init(struct domain *d) 
>  {
>      d->arch.vits = xzalloc(struct vgic_its);
>      if ( d->arch.vits == NULL )
> @@ -1516,9 +1544,10 @@ int vgic_its_domain_init(struct domain *d)
>      register_mmio_handler(d, &vgic_gits_mmio_handler, d->arch.vits->phys_base,
>                            SZ_64K);
>  
> -    return 0;
> +    return vgic_map_translation_space(d);
>  }
>  
> +
>  /*
>   * Local variables:
>   * mode: C
> -- 
> 1.7.9.5
> 

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

* Re: [RFC PATCH 14/19] xen/arm: vits: Map ITS translation space
  2015-03-03 17:31   ` Stefano Stabellini
@ 2015-03-03 17:41     ` Julien Grall
  0 siblings, 0 replies; 59+ messages in thread
From: Julien Grall @ 2015-03-03 17:41 UTC (permalink / raw)
  To: Stefano Stabellini, vijay.kilari
  Cc: Ian.Campbell, Prasun.Kapoor, Vijaya Kumar K, tim, xen-devel,
	stefano.stabellini, manish.jaggi

On 03/03/15 17:31, Stefano Stabellini wrote:
> On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> ITS translation space contains GITS_TRANSLATOR
>> register which is written by device to raise
>> LPI. This space needs to mapped to every domain
>> address space so that device can access GITS_TRANSLATOR
>> register using SMMU
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>> ---
>>  xen/arch/arm/vgic-v3-its.c |   33 +++++++++++++++++++++++++++++++--
>>  1 file changed, 31 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
>> index 48c880a..e7e587e 100644
>> --- a/xen/arch/arm/vgic-v3-its.c
>> +++ b/xen/arch/arm/vgic-v3-its.c
>> @@ -1504,7 +1504,35 @@ static const struct mmio_handler_ops vgic_gits_mmio_handler = {
>>      .write_handler = vgic_v3_gits_mmio_write,
>>  };
>>  
>> -int vgic_its_domain_init(struct domain *d)
>> +/*
>> + * Map the 64K ITS translation space in guest.
>> + * This is required purely for device smmu writes.
>> + */
>> +
>> +static int vgic_map_translation_space(struct domain *d)
>> +{
>> +    u64 addr, size;
>> +    int ret;
>> +    addr = d->arch.vits->phys_base + SZ_64K;
>> +    size = SZ_64K;
>> +
>> +    ret = map_mmio_regions(d,
>> +                           paddr_to_pfn(addr & PAGE_MASK),
>> +                           DIV_ROUND_UP(size, PAGE_SIZE),
>> +                           paddr_to_pfn(addr & PAGE_MASK));
>> +
>> +     if ( ret )
>> +     {
>> +          printk(XENLOG_ERR "Unable to map to dom%d access to"
>> +                 " 0x%"PRIx64" - 0x%"PRIx64"\n",
>> +                 d->domain_id,
>> +                 addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1);
>> +     }
>> +
>> +    return ret;
>> +}
> 
> Although we might want to map it 1:1 anyway, I think that this function
> should be able to cope with a virtual GITS_TRANSLATOR address different
> from the physical translator address.

FWIW, a 1:1 mapping won't work for guest.

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support
  2015-03-02 12:30 ` [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support vijay.kilari
  2015-03-02 14:17   ` Julien Grall
@ 2015-03-03 17:54   ` Stefano Stabellini
  1 sibling, 0 replies; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-03 17:54 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, Vijaya Kumar K,
	julien.grall, tim, xen-devel, stefano.stabellini, manish.jaggi

On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Introduce new fields in irq descriptors for
> LPI support. data field to hold irq related data
> and virq to hold virtual lpi number for the corresponding
> irq
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/irq.c        |   18 ++++++++++++++++++
>  xen/include/asm-arm/irq.h |    3 ++-
>  xen/include/xen/irq.h     |    2 ++
>  3 files changed, 22 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> index cb9c99b..d52ee0c 100644
> --- a/xen/arch/arm/irq.c
> +++ b/xen/arch/arm/irq.c
> @@ -89,6 +89,7 @@ static int __cpuinit init_local_irq_data(void)
>          init_one_irq_desc(desc);
>          desc->irq = irq;
>          desc->action  = NULL;
> +        desc->data = NULL;
>  
>          /* PPIs are included in local_irqs, we copy the IRQ type from
>           * local_irqs_type when bringing up local IRQ for this CPU in
> @@ -104,6 +105,23 @@ static int __cpuinit init_local_irq_data(void)
>      return 0;
>  }
>  
> +int irq_set_desc_data(unsigned int irq, void *d)
> +{
> +    unsigned long flags;
> +    struct irq_desc *desc = irq_to_desc(irq);
> +
> +    spin_lock_irqsave(&desc->lock, flags);
> +    desc->data = d;
> +    spin_unlock_irqrestore(&desc->lock, flags);
> +
> +    return 0;
> +}
> +
> +void *irq_get_desc_data(struct irq_desc *d)
> +{
> +    return d->data;

If you have spin_locks in irq_set_desc_data, you also need them in
irq_get_desc_data.


> +}
> +
>  void __init init_IRQ(void)
>  {
>      int irq;
> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
> index 435dfcd..de029e4 100644
> --- a/xen/include/asm-arm/irq.h
> +++ b/xen/include/asm-arm/irq.h
> @@ -46,7 +46,8 @@ void arch_move_irqs(struct vcpu *v);
>  
>  /* Set IRQ type for an SPI */
>  int irq_set_spi_type(unsigned int spi, unsigned int type);
> -
> +int irq_set_desc_data(unsigned int irq, void *d);
> +void *irq_get_desc_data(struct irq_desc *d);
>  int platform_get_irq(const struct dt_device_node *device, int index);
>  
>  void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
> diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
> index 9e0155c..f12afac 100644
> --- a/xen/include/xen/irq.h
> +++ b/xen/include/xen/irq.h
> @@ -91,6 +91,8 @@ typedef struct irq_desc {
>      spinlock_t lock;
>      struct arch_irq_desc arch;
>      cpumask_var_t affinity;
> +    void *data;   /* IRQ specific data */
> +    int virq;     /* Used to store vlpi */

I guess we didn't need to find the virq corresponding to a given
physical irq before, because we assumed 1:1.
Given that this struct is common with x86, I think it is best to add the
two new fields to struct arch_irq_desc.

virq should be unsigned int. Instead of another void* data, please add
struct vits_device *dev.


>      /* irq ratelimit */
>      s_time_t rl_quantum_start;
> -- 
> 1.7.9.5
> 

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

* Re: [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
  2015-03-02 12:30 ` [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling vijay.kilari
@ 2015-03-03 18:07   ` Stefano Stabellini
  2015-03-03 19:49     ` Julien Grall
  0 siblings, 1 reply; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-03 18:07 UTC (permalink / raw)
  To: vijay.kilari
  Cc: Ian.Campbell, stefano.stabellini, Prasun.Kapoor, Vijaya Kumar K,
	julien.grall, tim, xen-devel, stefano.stabellini, manish.jaggi

On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> 
> Add support for handling ITS(LPI) interrupts.
> The LPI interrupts are handled by physical ITS
> driver.
> 
> nested LPI interrupt handling is not tested and
> enabled.
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> ---
>  xen/arch/arm/gic-v3-its.c  |   31 +++++++++++++++++++++++++++++++
>  xen/arch/arm/gic-v3.c      |    8 ++++++--
>  xen/arch/arm/gic.c         |   38 ++++++++++++++++++++++++++++++++++++--
>  xen/arch/arm/irq.c         |   10 +++++++---
>  xen/arch/arm/vgic-v3-its.c |   10 ++++++++++
>  xen/arch/arm/vgic.c        |   14 ++++++++++----
>  xen/include/asm-arm/gic.h  |    3 +++
>  xen/include/asm-arm/irq.h  |    1 +
>  8 files changed, 104 insertions(+), 11 deletions(-)
> 
> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
> index b2c3320..7adbee4 100644
> --- a/xen/arch/arm/gic-v3-its.c
> +++ b/xen/arch/arm/gic-v3-its.c
> @@ -344,6 +344,37 @@ static const struct gic_its_hw_operations gic_its_ops = {
>      .gic_guest_lpi_type  = &gic_guest_its_type,
>  };
>  
> +void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs)
> +{
> +    struct domain *d;
> +    struct irq_desc *desc = irq_to_desc(irqnr);
> +
> +    irq_enter();
> +    spin_lock(&desc->lock);
> +
> +    if ( !desc->action )
> +    {
> +        printk("UNKNOWN LPI without handler\n");
> +        goto err;
> +    }
> +
> +    if ( desc->status & IRQ_GUEST )
> +    {
> +        d = irq_get_domain(desc);
> +
> +        desc->handler->end(desc);
> +
> +        desc->status |= IRQ_INPROGRESS;
> +        desc->arch.eoi_cpu = smp_processor_id();
> +
> +        /* XXX: inject irq into all guest vcpus */
> +        vgic_vcpu_inject_irq(d->vcpu[0], irqnr);
> +    }

Does it really need a separate handler? It seems to me that LPIs could
just be handled from do_IRQ like the rest.

Also the comment is wrong in this case.


> +err:
> +    spin_unlock(&desc->lock);
> +    irq_exit();
> +}
> +
>  static u64 its_cmd_ptr_to_offset(struct its_node *its,
>                                   struct its_cmd_block *ptr)
>  {
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index 02e71dd..b654535 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -848,9 +848,13 @@ static void gicv3_update_lr(int lr, const struct pending_irq *p,
>  
>      val =  (((uint64_t)state & 0x3) << GICH_LR_STATE_SHIFT) | grp;
>      val |= ((uint64_t)p->priority & 0xff) << GICH_LR_PRIORITY_SHIFT;
> -    val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;
>  
> -   if ( p->desc != NULL )
> +    if ( is_lpi(p->irq) )
> +        val |= ((uint64_t)p->desc->virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;
> +    else
> +        val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;

desc->virq should contain the right value for all interrupts, not just
lpis, so you should be able to do:

    val |= ((uint64_t)p->desc-virq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT;

in all cases.


> +   if ( p->desc != NULL && !(is_lpi(p->irq)) )
>         val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK)
>                             << GICH_LR_PHYSICAL_SHIFT);
>
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index fb77387..c4d352a 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -34,6 +34,7 @@
>  #include <asm/io.h>
>  #include <asm/gic.h>
>  #include <asm/vgic.h>
> +#include <asm/gic-its.h>
>  
>  static void gic_restore_pending_irqs(struct vcpu *v);
>  
> @@ -134,6 +135,21 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
>      gic_set_irq_properties(desc, cpu_mask, priority);
>  }
>  
> +void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
> +                            const cpumask_t *cpu_mask, unsigned int priority)
> +{
> +    struct pending_irq *p;
> +    ASSERT(spin_is_locked(&desc->lock));
> +
> +    desc->handler = gic_its_hw_ops->gic_guest_lpi_type;
> +    set_bit(_IRQ_GUEST, &desc->status);
> +
> +     
> +    /* TODO: do not assume delivery to vcpu0 */
> +    p = irq_to_pending(d->vcpu[0], desc->irq);
> +    p->desc = desc;
> +}
> +
>  /* Program the GIC to route an interrupt to a guest
>   *   - desc.lock must be held
>   */
> @@ -341,20 +357,33 @@ static void gic_update_one_lr(struct vcpu *v, int i)
>      struct pending_irq *p;
>      int irq;
>      struct gic_lr lr_val;
> +    uint32_t pirq;
>  
>      ASSERT(spin_is_locked(&v->arch.vgic.lock));
>      ASSERT(!local_irq_is_enabled());
>  
>      gic_hw_ops->read_lr(i, &lr_val);
>      irq = lr_val.virq;
> -    p = irq_to_pending(v, irq);
> +
> +    if ( is_lpi(irq) )
> +    {
> +        // Fetch corresponding plpi for vlpi
> +        if ( vgic_its_get_pid(v, irq, &pirq) )
> +            BUG();
> +        p = irq_to_pending(v, pirq);
> +        irq = pirq;
> +    }
> +    else
> +    {
> +        p = irq_to_pending(v, irq);

Shouldn't p->desc->irq return the pirq for LPIs too? If it doesn't, it
should :-)

I would like to see a more generic handling of virq != physical irq.
This is not specific to LPIs but to any scenario where the physical irq
differs from the virtual irq.


> +    }
>      if ( lr_val.state & GICH_LR_ACTIVE )
>      {
>          set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
>          if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) &&
>               test_and_clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status) )
>          {
> -            if ( p->desc == NULL )
> +            if ( p->desc == NULL  || is_lpi(irq) )

I thought that LPIs cannot be ACTIVE. If so, it is probably a mistake to
set an LPI GICH_LR_ACTIVE in the LR register.


>              {
>                   lr_val.state |= GICH_LR_PENDING;
>                   gic_hw_ops->write_lr(i, &lr_val);
> @@ -580,6 +609,11 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
>      do  {
>          /* Reading IRQ will ACK it */
>          irq = gic_hw_ops->read_irq();
> +        if ( is_lpi(irq) ) {
> +            // TODO: Enable irqs?
> +            its_handle_lpi(irq, regs);
> +            continue;
> +        }
>  
>          if ( likely(irq >= 16 && irq < 1021) )
>          {
> diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> index 13583b4..52371be 100644
> --- a/xen/arch/arm/irq.c
> +++ b/xen/arch/arm/irq.c
> @@ -276,7 +276,7 @@ void __cpuinit init_secondary_IRQ(void)
>      BUG_ON(init_local_irq_data() < 0);
>  }
>  
> -static inline struct domain *irq_get_domain(struct irq_desc *desc)
> +struct domain *irq_get_domain(struct irq_desc *desc)
>  {
>      ASSERT(spin_is_locked(&desc->lock));
>  
> @@ -603,9 +603,13 @@ int route_irq_to_guest(struct domain *d, unsigned int irq,
>      retval = __setup_irq(desc, 0, action);
>      if ( retval )
>          goto out;
> +    if ( irq >= NR_LOCAL_IRQS && irq < NR_IRQS)
> +        gic_route_irq_to_guest(d, desc, cpumask_of(smp_processor_id()),
> +                               GIC_PRI_IRQ);
> +    else
> +        gic_route_lpi_to_guest(d, desc, cpumask_of(smp_processor_id()),
> +                               GIC_PRI_IRQ);
>  
> -    gic_route_irq_to_guest(d, desc, cpumask_of(smp_processor_id()),
> -                           GIC_PRI_IRQ);
>      spin_unlock_irqrestore(&desc->lock, flags);
>      return 0;
>  
> diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
> index e7e587e..51b9614 100644
> --- a/xen/arch/arm/vgic-v3-its.c
> +++ b/xen/arch/arm/vgic-v3-its.c
> @@ -1022,6 +1022,16 @@ int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid)
>      return 1;
>  }
>  
> +uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid)
> +{
> +    uint8_t priority;
> +  
> +    priority =  readb_relaxed(v->domain->arch.vits->lpi_prop_page + pid);
> +    priority &= 0xfc;
> +
> +    return priority;
> +}

So it looks like we do handle priorities for LPIs, good! This doesn't
look like ITS specific, so we should move it vgic-v3.c


>  static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
>  {
>      uint32_t offset;
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 3bf9ef3..5571856 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -389,14 +389,20 @@ void vgic_clear_pending_irqs(struct vcpu *v)
>  void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq)
>  {
>      uint8_t priority;
> -    struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);
> +    struct vgic_irq_rank *rank;
>      struct pending_irq *iter, *n = irq_to_pending(v, irq);
>      unsigned long flags;
>      bool_t running;
>  
> -    vgic_lock_rank(v, rank, flags);
> -    priority = v->domain->arch.vgic.handler->get_irq_priority(v, irq);
> -    vgic_unlock_rank(v, rank, flags);
> +    if ( irq < NR_GIC_LPI )
> +    {
> +        rank = vgic_rank_irq(v, irq);
> +        vgic_lock_rank(v, rank, flags);
> +        priority = v->domain->arch.vgic.handler->get_irq_priority(v, irq);
> +        vgic_unlock_rank(v, rank, flags);
> +    }
> +    else
> +        priority = vgic_its_get_priority(v, irq);

I think that the handler should be set correctly for LPIs so that

priority = v->domain->arch.vgic.handler->get_irq_priority(v, irq);

works for them too without changes.


>      spin_lock_irqsave(&v->arch.vgic.lock, flags);
>  
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 6f2237f..075f488 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -220,6 +220,7 @@ enum gic_version {
>  
>  extern enum gic_version gic_hw_version(void);
>  extern void gic_eoi_irq(struct irq_desc *desc);
> +extern void its_handle_lpi(uint32_t irqnr, struct cpu_user_regs *regs);
>  /* Program the GIC to route an interrupt */
>  extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
>                                   unsigned int priority);
> @@ -356,6 +357,8 @@ void register_gic_ops(const struct gic_hw_operations *ops);
>  void register_gic_its_ops(const struct gic_its_hw_operations *ops);
>  int gic_make_node(const struct domain *d,const struct dt_device_node *node,
>                    void *fdt);
> +void gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
> +                            const cpumask_t *cpu_mask, unsigned int priority);
>  
>  #endif /* __ASSEMBLY__ */
>  #endif
> diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
> index 1159a6d..19246f9 100644
> --- a/xen/include/asm-arm/irq.h
> +++ b/xen/include/asm-arm/irq.h
> @@ -51,6 +51,7 @@ int irq_set_spi_type(unsigned int spi, unsigned int type);
>  int irq_set_desc_data(unsigned int irq, void *d);
>  void *irq_get_desc_data(struct irq_desc *d);
>  int platform_get_irq(const struct dt_device_node *device, int index);
> +struct domain *irq_get_domain(struct irq_desc *desc);
>  
>  void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask);
>  
> -- 
> 1.7.9.5
> 

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

* Re: [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
  2015-03-03 18:07   ` Stefano Stabellini
@ 2015-03-03 19:49     ` Julien Grall
  2015-03-04  9:57       ` Stefano Stabellini
  0 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-03 19:49 UTC (permalink / raw)
  To: Stefano Stabellini, vijay.kilari
  Cc: Ian.Campbell, Prasun.Kapoor, Vijaya Kumar K, tim, xen-devel,
	stefano.stabellini, manish.jaggi

Hi Stefano,

On 03/03/2015 18:07, Stefano Stabellini wrote:
> I would like to see a more generic handling of virq != physical irq.
> This is not specific to LPIs but to any scenario where the physical irq
> differs from the virtual irq.

I though we talked about it during the meeting at Connect...

I've already got a patch for making virq != pirq :
https://patches.linaro.org/43012/

That would drop the static 8K added because of the changes in irq_desc.

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling
  2015-03-03 19:49     ` Julien Grall
@ 2015-03-04  9:57       ` Stefano Stabellini
  0 siblings, 0 replies; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-04  9:57 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian.Campbell, vijay.kilari, Stefano Stabellini, Prasun.Kapoor,
	Vijaya Kumar K, tim, xen-devel, stefano.stabellini, manish.jaggi

On Tue, 3 Mar 2015, Julien Grall wrote:
> Hi Stefano,
> 
> On 03/03/2015 18:07, Stefano Stabellini wrote:
> > I would like to see a more generic handling of virq != physical irq.
> > This is not specific to LPIs but to any scenario where the physical irq
> > differs from the virtual irq.
> 
> I though we talked about it during the meeting at Connect...
> 
> I've already got a patch for making virq != pirq :
> https://patches.linaro.org/43012/
> 
> That would drop the static 8K added because of the changes in irq_desc.

I was pretty sure you had a patch for this already but I didn't have a
link to it ready. Your patch could be a requirement for this series.

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

* Re: [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs
  2015-03-03 17:16   ` Stefano Stabellini
@ 2015-03-04 12:10     ` Stefano Stabellini
  0 siblings, 0 replies; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-04 12:10 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Ian.Campbell, vijay.kilari, Prasun.Kapoor, Vijaya Kumar K,
	julien.grall, tim, xen-devel, stefano.stabellini, manish.jaggi

On Tue, 3 Mar 2015, Stefano Stabellini wrote:
> On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
> > @@ -94,19 +95,29 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
> >      switch ( gicr_reg )
> >      {
> >      case GICR_CTLR:
> > -        /* We have not implemented LPI's, read zero */
> > -        goto read_as_zero;
> > +        /*
> > +         * Enable LPI's for ITS. Direct injection of LPI
> > +         * by writing to GICR_{SET,CLR}LPIR are not supported
> > +         */
> 
> Is this actually a limitation that we can have? Is there a way to
> communicate to the guest OS that GICR_{SET,CLR}LPIR are not supported?

Actually the GICv3 spec says:

Note: this register is mandatory in an implementation that supports LPIs
and does not include an ITS. The register location is IMPLEMENTATION
DEFINED in an implementation that does include an ITS.

So, if we include the vITS, does this mean that we can simply make this
register disappear?


> 
> > +        if ( dabt.size != DABT_WORD ) goto bad_width;
> > +        vgic_lock(v);
> > +        *r = v->domain->arch.vgic.gicr_ctlr;
> > +        vgic_unlock(v);
> > +        return 1;
> >      case GICR_IIDR:
> >          if ( dabt.size != DABT_WORD ) goto bad_width;
> >          *r = GICV3_GICR_IIDR_VAL;
> >          return 1;
> >      case GICR_TYPER:
> > -        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> > -        /* TBD: Update processor id in [23:8] when ITS support is added */
> > +        if ( dabt.size != DABT_WORD && dabt.size != DABT_DOUBLE_WORD )
> > +            goto bad_width;
> > +        /* XXX: Update processor id in [23:8] if GITS_TYPER: PTA is not set */
> >          aff = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 56 |
> >                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 |
> >                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 |
> >                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32);
> > +        /* Set LPI support */
> > +        aff |= (GICR_TYPER_DISTRIBUTED_IMP | GICR_TYPER_PLPIS);
> >          *r = aff;
> >          return 1;
> >      case GICR_STATUSR:

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-03 11:43     ` Julien Grall
@ 2015-03-09 12:57       ` Vijay Kilari
  2015-03-09 16:06         ` Stefano Stabellini
  2015-03-09 18:16         ` Julien Grall
  0 siblings, 2 replies; 59+ messages in thread
From: Vijay Kilari @ 2015-03-09 12:57 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Tue, Mar 3, 2015 at 5:13 PM, Julien Grall <julien.grall@linaro.org> wrote:
> Hello Vijay,
>
> On 03/03/2015 03:55, Vijay Kilari wrote:
>>
>> On Mon, Mar 2, 2015 at 6:49 PM, Julien Grall <julien.grall@linaro.org>
>> wrote:
>>>
>>> On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
>>>>
>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>
>>>> Add ITS support for arm. Following major features
>>>> are supported
>>>>   - GICv3 ITS support for arm64 platform
>>>>   - Supports only single ITS node
>>>
>>>
>>> Why only one ITS node supported? I though Cavium was using 2 ITS...
>>
>>
>> I will update for 2 ITS nodes later when NUMA is supported
>
>
> Why do you speak about NUMA? AFAICT, there is no requirement to support NUMA
> for having multiple ITS...
>
> With multiple ITS support, your vITS emulation will likely heavily change.
> So it would be nice to have this support as soon as possible.

Incremental changes (as separate patch series)
would be more meaningful. I will have a look at it
and if possible I will incorporate in next series

>
>>>
>>>>   - LPI descriptors are allocated on-demand
>>>>   - Only ITS Dom0 is supported
>>>
>>>
>>> Any plan to support guest?
>>
>>
>> Yes, I will do it in next version
>
>
> What is missing to support guest? Only the toolstack part?

Yes, it is only toolstack part similar to GICv3

>
>>>
>>>> Vijaya Kumar K (19):
>>>>    xen/arm: add linked list apis
>>>>    xen/arm: its: Import GICv3 ITS driver from linux
>>>>    xen/arm: its: Port ITS driver to xen
>>>
>>>
>>> A general comment (I haven't read closely the patches). The GICv3 ITS
>>> taken from Linux is modified so heavily (rename function, move out code,
>>> dropping unused code...) that your assumption in patch #1 [1] is wrong.
>>>
>>> At the end of this series it would make impossible to backport patch
>>> from Linux.
>>
>>
>>    Most of the code is reused or moved to different file based on Xen
>> requirement.
>>      - code like msi registered callback (setup_irq & teardown_irq) is of
>> no use in Xen. So removed
>>      - irq_chip is different in linux
>>      - some of the functions like encode of ITS commands can be used in
>> virtual ITS
>>        driver as well. So have to be moved out to header file
>>      - the LPI allocation is moved to virtual ITS driver. We can
>> consider it keeping in physical ITS
>>        driver but it fits well in virtual ITS driver rather than
>> physical ITS driver.
>
>
> IHMO, moving the code around two files make the code more difficult to
> review because the patch is bigger.
>
> That also means we can't really review the first couple of patches because
> the code will change a lot after.
>
> But the maintainers may be disagree with me...
>
>>>
>>> Regards,
>>>
>>> [1] "This is actual GICv3 ITS driver from Linux. [..] This helps to
>>> import any issues found in Linux"
>>
>>
>> I have kept the linux GICv3 ITS driver in first patch and made incremental
>> changes just to have better understanding and incremental approach
>
>
> But this is doesn't help to backport issue from Linux...
>
> BTW, do you have a tree with all the code?

Yes, I have a tree, But I cannot share it. Github is ok?

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

* Re: [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller for LPIs
  2015-03-03 17:28   ` Stefano Stabellini
@ 2015-03-09 13:03     ` Vijay Kilari
  2015-03-09 16:09       ` Stefano Stabellini
  0 siblings, 1 reply; 59+ messages in thread
From: Vijay Kilari @ 2015-03-09 13:03 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Ian Campbell, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Tue, Mar 3, 2015 at 10:58 PM, Stefano Stabellini
<stefano.stabellini@eu.citrix.com> wrote:
> On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> This patch implements hw_irq_controller api's required
>> to handle LPI's.
>>
>> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>> ---
>>  xen/arch/arm/gic-v3-its.c |  104 ++++++++++++++++++++++++++++++++++++++++++++-
>>  xen/arch/arm/gic.c        |   11 +++++
>>  xen/include/asm-arm/gic.h |    8 +++-
>>  3 files changed, 121 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
>> index 5d9550f..b2c3320 100644
>> --- a/xen/arch/arm/gic-v3-its.c
>> +++ b/xen/arch/arm/gic-v3-its.c
>> @@ -140,6 +140,9 @@ struct its_cmd_desc {
>>  typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
>>                                  struct its_cmd_desc *);
>>
>> +static void its_send_movi(struct its_node *its, struct its_collection *col,
>> +                          u32 dev_id, u32 id);
>> +
>>  uint32_t its_get_pta_type(void)
>>  {
>>      return pta_type;
>> @@ -244,6 +247,103 @@ int its_get_physical_cid(uint32_t *col_id, uint64_t vta)
>>      return 1;
>>  }
>>
>> +static void lpi_set_config(u32 hwirq, u32 id, int enable)
>> +{
>> +    u8 *cfg;
>> +
>> +    cfg = gic_rdists->prop_page + hwirq - NR_GIC_LPI;
>> +
>> +    if ( enable )
>> +        *cfg |= (1 << 0);
>> +    else
>> +        *cfg &= ~(1 << 0);
>> +
>> +    /*
>> +     * Make the above write visible to the redistributors.
>> +     * And yes, we're flushing exactly: One. Single. Byte.
>> +     * Humpf...
>> +     */
>> +    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
>> +        clean_dcache_va_range(cfg, sizeof(*cfg));
>> +    else
>> +        dsb(ishst);
>> +}
>> +
>> +static void its_mask_irq(struct irq_desc *d)
>> +{
>> +    u32 id;
>> +
>> +    id = d->irq;
>> +    set_bit(_IRQ_DISABLED, &d->status);
>> +    lpi_set_config(d->irq, id, 0);
>> +}
>> +
>> +static void its_unmask_irq(struct irq_desc *d)
>> +{
>> +    u32 id;
>> +
>> +    id = d->irq;
>> +    clear_bit(_IRQ_DISABLED, &d->status);
>> +    lpi_set_config(d->irq, id, 1);
>> +}
>> +
>> +static unsigned int its_irq_startup(struct irq_desc *desc)
>> +{
>> +    its_unmask_irq(desc);
>> +
>> +    return 0;
>> +}
>> +
>> +static void its_irq_shutdown(struct irq_desc *desc)
>> +{
>> +    its_mask_irq(desc);
>> +}
>> +
>> +static void its_eoi_irq(struct irq_desc *d)
>> +{
>> +    gic_eoi_irq(d);
>> +}
>> +
>> +static void its_ack_irq(struct irq_desc *desc)
>> +{
>> +    /* No ACK -- reading IAR has done this for us */
>> +}
>> +
>> +static void its_set_affinity(struct irq_desc *d, const cpumask_t *mask_val)
>> +{
>> +    /* XXX: check cpumask_any or cpu_online_map is ok? */
>> +    cpumask_t online_mask;
>> +    unsigned int cpu;
>> +    struct vits_device *its_dev = irq_get_desc_data(d);
>> +    struct its_collection *target_col;
>> +    uint32_t id;
>> +
>> +    cpumask_and(&online_mask, mask_val, &cpu_online_map);
>> +    cpu = cpumask_any(&online_mask);
>> +    /* Physical collection id */
>> +    target_col = &its->collections[cpu];
>> +    /* Physical irq is considered not virq */
>> +    id = d->irq;
>> +
>> +    its_send_movi(its, target_col, its_dev->dev_id, id);
>> +}
>> +
>> +/* TODO: To implement set_affinity */
>> +static const hw_irq_controller gic_guest_its_type = {
>> +    .typename     = "gic-its",
>> +    .startup      = its_irq_startup,
>> +    .shutdown     = its_irq_shutdown,
>> +    .enable       = its_unmask_irq,
>> +    .disable      = its_mask_irq,
>> +    .ack          = its_ack_irq,
>> +    .end          = its_eoi_irq,
>> +    .set_affinity = its_set_affinity,
>> +};
>> +
>> +static const struct gic_its_hw_operations gic_its_ops = {
>> +    .gic_guest_lpi_type  = &gic_guest_its_type,
>> +};
>
> Aside from the one call to its_send_movi, nothing here is ITS specific.
> In fact I would just move all this to gic-v3.c as it feels like part of
> the GICv3 driver rather than the ITS driver.

its_mask_irq(), its_umask_irq() & its_set_affinity() are different for ITS.

>
>
>>  static u64 its_cmd_ptr_to_offset(struct its_node *its,
>>                                   struct its_cmd_block *ptr)
>>  {
>> @@ -392,7 +492,7 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col,
>>      its_send_single_command(its, its_build_mapc_cmd, &desc);
>>  }
>>
>> -void its_send_movi(struct its_node *its, struct its_collection *col,
>> +static void its_send_movi(struct its_node *its, struct its_collection *col,
>>                     u32 dev_id, u32 id)
>>  {
>>      struct its_cmd_desc desc;
>> @@ -872,6 +972,8 @@ int its_init(struct dt_device_node *node, struct rdist_prop *rdists)
>>
>>      its_alloc_lpi_tables();
>>
>> +    register_gic_its_ops(&gic_its_ops);
>> +
>>      return 0;
>>  }
>>
>> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
>> index 390c8b0..fb77387 100644
>> --- a/xen/arch/arm/gic.c
>> +++ b/xen/arch/arm/gic.c
>> @@ -46,12 +46,18 @@ static DEFINE_PER_CPU(uint64_t, lr_mask);
>>  static void gic_update_one_lr(struct vcpu *v, int i);
>>
>>  static const struct gic_hw_operations *gic_hw_ops;
>> +static const struct gic_its_hw_operations *gic_its_hw_ops;
>>
>>  void register_gic_ops(const struct gic_hw_operations *ops)
>>  {
>>      gic_hw_ops = ops;
>>  }
>>
>> +void register_gic_its_ops(const struct gic_its_hw_operations *ops)
>> +{
>> +    gic_its_hw_ops = ops;
>> +}
>
> Not clear why you need this.

This is registered to gic driver and the .gic_guest_lpi_type
field in  gic_its_hw_operations is used to update desc->handler
of ITS descriptor

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-09 12:57       ` Vijay Kilari
@ 2015-03-09 16:06         ` Stefano Stabellini
  2015-03-09 18:16         ` Julien Grall
  1 sibling, 0 replies; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-09 16:06 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Julien Grall, Tim Deegan, xen-devel, Stefano Stabellini,
	manish.jaggi

On Mon, 9 Mar 2015, Vijay Kilari wrote:
> On Tue, Mar 3, 2015 at 5:13 PM, Julien Grall <julien.grall@linaro.org> wrote:
> > Hello Vijay,
> >
> > On 03/03/2015 03:55, Vijay Kilari wrote:
> >>
> >> On Mon, Mar 2, 2015 at 6:49 PM, Julien Grall <julien.grall@linaro.org>
> >> wrote:
> >>>
> >>> On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
> >>>>
> >>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> >>>>
> >>>> Add ITS support for arm. Following major features
> >>>> are supported
> >>>>   - GICv3 ITS support for arm64 platform
> >>>>   - Supports only single ITS node
> >>>
> >>>
> >>> Why only one ITS node supported? I though Cavium was using 2 ITS...
> >>
> >>
> >> I will update for 2 ITS nodes later when NUMA is supported
> >
> >
> > Why do you speak about NUMA? AFAICT, there is no requirement to support NUMA
> > for having multiple ITS...
> >
> > With multiple ITS support, your vITS emulation will likely heavily change.
> > So it would be nice to have this support as soon as possible.
> 
> Incremental changes (as separate patch series)
> would be more meaningful. I will have a look at it
> and if possible I will incorporate in next series
> 
> >
> >>>
> >>>>   - LPI descriptors are allocated on-demand
> >>>>   - Only ITS Dom0 is supported
> >>>
> >>>
> >>> Any plan to support guest?
> >>
> >>
> >> Yes, I will do it in next version
> >
> >
> > What is missing to support guest? Only the toolstack part?
> 
> Yes, it is only toolstack part similar to GICv3
> 
> >
> >>>
> >>>> Vijaya Kumar K (19):
> >>>>    xen/arm: add linked list apis
> >>>>    xen/arm: its: Import GICv3 ITS driver from linux
> >>>>    xen/arm: its: Port ITS driver to xen
> >>>
> >>>
> >>> A general comment (I haven't read closely the patches). The GICv3 ITS
> >>> taken from Linux is modified so heavily (rename function, move out code,
> >>> dropping unused code...) that your assumption in patch #1 [1] is wrong.
> >>>
> >>> At the end of this series it would make impossible to backport patch
> >>> from Linux.
> >>
> >>
> >>    Most of the code is reused or moved to different file based on Xen
> >> requirement.
> >>      - code like msi registered callback (setup_irq & teardown_irq) is of
> >> no use in Xen. So removed
> >>      - irq_chip is different in linux
> >>      - some of the functions like encode of ITS commands can be used in
> >> virtual ITS
> >>        driver as well. So have to be moved out to header file
> >>      - the LPI allocation is moved to virtual ITS driver. We can
> >> consider it keeping in physical ITS
> >>        driver but it fits well in virtual ITS driver rather than
> >> physical ITS driver.
> >
> >
> > IHMO, moving the code around two files make the code more difficult to
> > review because the patch is bigger.
> >
> > That also means we can't really review the first couple of patches because
> > the code will change a lot after.
> >
> > But the maintainers may be disagree with me...
> >
> >>>
> >>> Regards,
> >>>
> >>> [1] "This is actual GICv3 ITS driver from Linux. [..] This helps to
> >>> import any issues found in Linux"
> >>
> >>
> >> I have kept the linux GICv3 ITS driver in first patch and made incremental
> >> changes just to have better understanding and incremental approach
> >
> >
> > But this is doesn't help to backport issue from Linux...
> >
> > BTW, do you have a tree with all the code?
> 
> Yes, I have a tree, But I cannot share it. Github is ok?

Github is fine.

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

* Re: [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller for LPIs
  2015-03-09 13:03     ` Vijay Kilari
@ 2015-03-09 16:09       ` Stefano Stabellini
  2015-03-09 16:32         ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-09 16:09 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Julien Grall, Tim Deegan, xen-devel, Stefano Stabellini,
	manish.jaggi

On Mon, 9 Mar 2015, Vijay Kilari wrote:
> On Tue, Mar 3, 2015 at 10:58 PM, Stefano Stabellini
> <stefano.stabellini@eu.citrix.com> wrote:
> > On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
> >> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> >>
> >> This patch implements hw_irq_controller api's required
> >> to handle LPI's.
> >>
> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> >> ---
> >>  xen/arch/arm/gic-v3-its.c |  104 ++++++++++++++++++++++++++++++++++++++++++++-
> >>  xen/arch/arm/gic.c        |   11 +++++
> >>  xen/include/asm-arm/gic.h |    8 +++-
> >>  3 files changed, 121 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
> >> index 5d9550f..b2c3320 100644
> >> --- a/xen/arch/arm/gic-v3-its.c
> >> +++ b/xen/arch/arm/gic-v3-its.c
> >> @@ -140,6 +140,9 @@ struct its_cmd_desc {
> >>  typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
> >>                                  struct its_cmd_desc *);
> >>
> >> +static void its_send_movi(struct its_node *its, struct its_collection *col,
> >> +                          u32 dev_id, u32 id);
> >> +
> >>  uint32_t its_get_pta_type(void)
> >>  {
> >>      return pta_type;
> >> @@ -244,6 +247,103 @@ int its_get_physical_cid(uint32_t *col_id, uint64_t vta)
> >>      return 1;
> >>  }
> >>
> >> +static void lpi_set_config(u32 hwirq, u32 id, int enable)
> >> +{
> >> +    u8 *cfg;
> >> +
> >> +    cfg = gic_rdists->prop_page + hwirq - NR_GIC_LPI;
> >> +
> >> +    if ( enable )
> >> +        *cfg |= (1 << 0);
> >> +    else
> >> +        *cfg &= ~(1 << 0);
> >> +
> >> +    /*
> >> +     * Make the above write visible to the redistributors.
> >> +     * And yes, we're flushing exactly: One. Single. Byte.
> >> +     * Humpf...
> >> +     */
> >> +    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
> >> +        clean_dcache_va_range(cfg, sizeof(*cfg));
> >> +    else
> >> +        dsb(ishst);
> >> +}
> >> +
> >> +static void its_mask_irq(struct irq_desc *d)
> >> +{
> >> +    u32 id;
> >> +
> >> +    id = d->irq;
> >> +    set_bit(_IRQ_DISABLED, &d->status);
> >> +    lpi_set_config(d->irq, id, 0);
> >> +}
> >> +
> >> +static void its_unmask_irq(struct irq_desc *d)
> >> +{
> >> +    u32 id;
> >> +
> >> +    id = d->irq;
> >> +    clear_bit(_IRQ_DISABLED, &d->status);
> >> +    lpi_set_config(d->irq, id, 1);
> >> +}
> >> +
> >> +static unsigned int its_irq_startup(struct irq_desc *desc)
> >> +{
> >> +    its_unmask_irq(desc);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static void its_irq_shutdown(struct irq_desc *desc)
> >> +{
> >> +    its_mask_irq(desc);
> >> +}
> >> +
> >> +static void its_eoi_irq(struct irq_desc *d)
> >> +{
> >> +    gic_eoi_irq(d);
> >> +}
> >> +
> >> +static void its_ack_irq(struct irq_desc *desc)
> >> +{
> >> +    /* No ACK -- reading IAR has done this for us */
> >> +}
> >> +
> >> +static void its_set_affinity(struct irq_desc *d, const cpumask_t *mask_val)
> >> +{
> >> +    /* XXX: check cpumask_any or cpu_online_map is ok? */
> >> +    cpumask_t online_mask;
> >> +    unsigned int cpu;
> >> +    struct vits_device *its_dev = irq_get_desc_data(d);
> >> +    struct its_collection *target_col;
> >> +    uint32_t id;
> >> +
> >> +    cpumask_and(&online_mask, mask_val, &cpu_online_map);
> >> +    cpu = cpumask_any(&online_mask);
> >> +    /* Physical collection id */
> >> +    target_col = &its->collections[cpu];
> >> +    /* Physical irq is considered not virq */
> >> +    id = d->irq;
> >> +
> >> +    its_send_movi(its, target_col, its_dev->dev_id, id);
> >> +}
> >> +
> >> +/* TODO: To implement set_affinity */
> >> +static const hw_irq_controller gic_guest_its_type = {
> >> +    .typename     = "gic-its",
> >> +    .startup      = its_irq_startup,
> >> +    .shutdown     = its_irq_shutdown,
> >> +    .enable       = its_unmask_irq,
> >> +    .disable      = its_mask_irq,
> >> +    .ack          = its_ack_irq,
> >> +    .end          = its_eoi_irq,
> >> +    .set_affinity = its_set_affinity,
> >> +};
> >> +
> >> +static const struct gic_its_hw_operations gic_its_ops = {
> >> +    .gic_guest_lpi_type  = &gic_guest_its_type,
> >> +};
> >
> > Aside from the one call to its_send_movi, nothing here is ITS specific.
> > In fact I would just move all this to gic-v3.c as it feels like part of
> > the GICv3 driver rather than the ITS driver.
> 
> its_mask_irq(), its_umask_irq() & its_set_affinity() are different for ITS.

It looks like they are different because they deal with LPIs. If that is
the only difference, then I think they should be in gic-v3.c. LPIs in
general works regardless of the presence of an ITS, right?


> >
> >
> >>  static u64 its_cmd_ptr_to_offset(struct its_node *its,
> >>                                   struct its_cmd_block *ptr)
> >>  {
> >> @@ -392,7 +492,7 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col,
> >>      its_send_single_command(its, its_build_mapc_cmd, &desc);
> >>  }
> >>
> >> -void its_send_movi(struct its_node *its, struct its_collection *col,
> >> +static void its_send_movi(struct its_node *its, struct its_collection *col,
> >>                     u32 dev_id, u32 id)
> >>  {
> >>      struct its_cmd_desc desc;
> >> @@ -872,6 +972,8 @@ int its_init(struct dt_device_node *node, struct rdist_prop *rdists)
> >>
> >>      its_alloc_lpi_tables();
> >>
> >> +    register_gic_its_ops(&gic_its_ops);
> >> +
> >>      return 0;
> >>  }
> >>
> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> >> index 390c8b0..fb77387 100644
> >> --- a/xen/arch/arm/gic.c
> >> +++ b/xen/arch/arm/gic.c
> >> @@ -46,12 +46,18 @@ static DEFINE_PER_CPU(uint64_t, lr_mask);
> >>  static void gic_update_one_lr(struct vcpu *v, int i);
> >>
> >>  static const struct gic_hw_operations *gic_hw_ops;
> >> +static const struct gic_its_hw_operations *gic_its_hw_ops;
> >>
> >>  void register_gic_ops(const struct gic_hw_operations *ops)
> >>  {
> >>      gic_hw_ops = ops;
> >>  }
> >>
> >> +void register_gic_its_ops(const struct gic_its_hw_operations *ops)
> >> +{
> >> +    gic_its_hw_ops = ops;
> >> +}
> >
> > Not clear why you need this.
> 
> This is registered to gic driver and the .gic_guest_lpi_type
> field in  gic_its_hw_operations is used to update desc->handler
> of ITS descriptor
> 

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

* Re: [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller for LPIs
  2015-03-09 16:09       ` Stefano Stabellini
@ 2015-03-09 16:32         ` Vijay Kilari
  0 siblings, 0 replies; 59+ messages in thread
From: Vijay Kilari @ 2015-03-09 16:32 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: Ian Campbell, Prasun Kapoor, Vijaya Kumar K, Julien Grall,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Mon, Mar 9, 2015 at 9:39 PM, Stefano Stabellini
<stefano.stabellini@eu.citrix.com> wrote:
> On Mon, 9 Mar 2015, Vijay Kilari wrote:
>> On Tue, Mar 3, 2015 at 10:58 PM, Stefano Stabellini
>> <stefano.stabellini@eu.citrix.com> wrote:
>> > On Mon, 2 Mar 2015, vijay.kilari@gmail.com wrote:
>> >> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>> >>
>> >> This patch implements hw_irq_controller api's required
>> >> to handle LPI's.
>> >>
>> >> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>> >> ---
>> >>  xen/arch/arm/gic-v3-its.c |  104 ++++++++++++++++++++++++++++++++++++++++++++-
>> >>  xen/arch/arm/gic.c        |   11 +++++
>> >>  xen/include/asm-arm/gic.h |    8 +++-
>> >>  3 files changed, 121 insertions(+), 2 deletions(-)
>> >>
>> >> diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
>> >> index 5d9550f..b2c3320 100644
>> >> --- a/xen/arch/arm/gic-v3-its.c
>> >> +++ b/xen/arch/arm/gic-v3-its.c
>> >> @@ -140,6 +140,9 @@ struct its_cmd_desc {
>> >>  typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *,
>> >>                                  struct its_cmd_desc *);
>> >>
>> >> +static void its_send_movi(struct its_node *its, struct its_collection *col,
>> >> +                          u32 dev_id, u32 id);
>> >> +
>> >>  uint32_t its_get_pta_type(void)
>> >>  {
>> >>      return pta_type;
>> >> @@ -244,6 +247,103 @@ int its_get_physical_cid(uint32_t *col_id, uint64_t vta)
>> >>      return 1;
>> >>  }
>> >>
>> >> +static void lpi_set_config(u32 hwirq, u32 id, int enable)
>> >> +{
>> >> +    u8 *cfg;
>> >> +
>> >> +    cfg = gic_rdists->prop_page + hwirq - NR_GIC_LPI;
>> >> +
>> >> +    if ( enable )
>> >> +        *cfg |= (1 << 0);
>> >> +    else
>> >> +        *cfg &= ~(1 << 0);
>> >> +
>> >> +    /*
>> >> +     * Make the above write visible to the redistributors.
>> >> +     * And yes, we're flushing exactly: One. Single. Byte.
>> >> +     * Humpf...
>> >> +     */
>> >> +    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
>> >> +        clean_dcache_va_range(cfg, sizeof(*cfg));
>> >> +    else
>> >> +        dsb(ishst);
>> >> +}
>> >> +
>> >> +static void its_mask_irq(struct irq_desc *d)
>> >> +{
>> >> +    u32 id;
>> >> +
>> >> +    id = d->irq;
>> >> +    set_bit(_IRQ_DISABLED, &d->status);
>> >> +    lpi_set_config(d->irq, id, 0);
>> >> +}
>> >> +
>> >> +static void its_unmask_irq(struct irq_desc *d)
>> >> +{
>> >> +    u32 id;
>> >> +
>> >> +    id = d->irq;
>> >> +    clear_bit(_IRQ_DISABLED, &d->status);
>> >> +    lpi_set_config(d->irq, id, 1);
>> >> +}
>> >> +
>> >> +static unsigned int its_irq_startup(struct irq_desc *desc)
>> >> +{
>> >> +    its_unmask_irq(desc);
>> >> +
>> >> +    return 0;
>> >> +}
>> >> +
>> >> +static void its_irq_shutdown(struct irq_desc *desc)
>> >> +{
>> >> +    its_mask_irq(desc);
>> >> +}
>> >> +
>> >> +static void its_eoi_irq(struct irq_desc *d)
>> >> +{
>> >> +    gic_eoi_irq(d);
>> >> +}
>> >> +
>> >> +static void its_ack_irq(struct irq_desc *desc)
>> >> +{
>> >> +    /* No ACK -- reading IAR has done this for us */
>> >> +}
>> >> +
>> >> +static void its_set_affinity(struct irq_desc *d, const cpumask_t *mask_val)
>> >> +{
>> >> +    /* XXX: check cpumask_any or cpu_online_map is ok? */
>> >> +    cpumask_t online_mask;
>> >> +    unsigned int cpu;
>> >> +    struct vits_device *its_dev = irq_get_desc_data(d);
>> >> +    struct its_collection *target_col;
>> >> +    uint32_t id;
>> >> +
>> >> +    cpumask_and(&online_mask, mask_val, &cpu_online_map);
>> >> +    cpu = cpumask_any(&online_mask);
>> >> +    /* Physical collection id */
>> >> +    target_col = &its->collections[cpu];
>> >> +    /* Physical irq is considered not virq */
>> >> +    id = d->irq;
>> >> +
>> >> +    its_send_movi(its, target_col, its_dev->dev_id, id);
>> >> +}
>> >> +
>> >> +/* TODO: To implement set_affinity */
>> >> +static const hw_irq_controller gic_guest_its_type = {
>> >> +    .typename     = "gic-its",
>> >> +    .startup      = its_irq_startup,
>> >> +    .shutdown     = its_irq_shutdown,
>> >> +    .enable       = its_unmask_irq,
>> >> +    .disable      = its_mask_irq,
>> >> +    .ack          = its_ack_irq,
>> >> +    .end          = its_eoi_irq,
>> >> +    .set_affinity = its_set_affinity,
>> >> +};
>> >> +
>> >> +static const struct gic_its_hw_operations gic_its_ops = {
>> >> +    .gic_guest_lpi_type  = &gic_guest_its_type,
>> >> +};
>> >
>> > Aside from the one call to its_send_movi, nothing here is ITS specific.
>> > In fact I would just move all this to gic-v3.c as it feels like part of
>> > the GICv3 driver rather than the ITS driver.
>>
>> its_mask_irq(), its_umask_irq() & its_set_affinity() are different for ITS.
>
> It looks like they are different because they deal with LPIs. If that is
> the only difference, then I think they should be in gic-v3.c. LPIs in
> general works regardless of the presence of an ITS, right?

OK. I will take care. Yes LPI works without ITS using GICR_{SET,CLR}LPIR
registers. I have not added this support for now.

Regards
Vijay

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-09 12:57       ` Vijay Kilari
  2015-03-09 16:06         ` Stefano Stabellini
@ 2015-03-09 18:16         ` Julien Grall
  2015-03-13  4:48           ` Vijay Kilari
  1 sibling, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-09 18:16 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hello Vijay,

On 09/03/2015 14:57, Vijay Kilari wrote:
> On Tue, Mar 3, 2015 at 5:13 PM, Julien Grall <julien.grall@linaro.org> wrote:
>> Hello Vijay,
>>
>> On 03/03/2015 03:55, Vijay Kilari wrote:
>>>
>>> On Mon, Mar 2, 2015 at 6:49 PM, Julien Grall <julien.grall@linaro.org>
>>> wrote:
>>>>
>>>> On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
>>>>>
>>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>>
>>>>> Add ITS support for arm. Following major features
>>>>> are supported
>>>>>    - GICv3 ITS support for arm64 platform
>>>>>    - Supports only single ITS node
>>>>
>>>>
>>>> Why only one ITS node supported? I though Cavium was using 2 ITS...
>>>
>>>
>>> I will update for 2 ITS nodes later when NUMA is supported
>>
>>
>> Why do you speak about NUMA? AFAICT, there is no requirement to support NUMA
>> for having multiple ITS...
>>
>> With multiple ITS support, your vITS emulation will likely heavily change.
>> So it would be nice to have this support as soon as possible.
>
> Incremental changes (as separate patch series)
> would be more meaningful. I will have a look at it
> and if possible I will incorporate in next series

It doesn't make sense to not support multiple ITS from the beginning.

FWIW, your code is based on the Linux driver which support multiple ITS. 
So why did you drop this support?

Anyway, I'm pretty sure you will have to rework the vITS with the 
support of multiple ITS... Having a separate patch means more work for 
all of us: more series and more review.

>> What is missing to support guest? Only the toolstack part?
>
> Yes, it is only toolstack part similar to GICv3

Ok.

>> BTW, do you have a tree with all the code?
>
> Yes, I have a tree, But I cannot share it. Github is ok?

Sure.


Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-09 18:16         ` Julien Grall
@ 2015-03-13  4:48           ` Vijay Kilari
  2015-03-13 10:13             ` Julien Grall
  0 siblings, 1 reply; 59+ messages in thread
From: Vijay Kilari @ 2015-03-13  4:48 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hi Julien,

On Mon, Mar 9, 2015 at 11:46 PM, Julien Grall <julien.grall@linaro.org> wrote:
> Hello Vijay,
>
> On 09/03/2015 14:57, Vijay Kilari wrote:
>>
>> On Tue, Mar 3, 2015 at 5:13 PM, Julien Grall <julien.grall@linaro.org>
>> wrote:
>>>
>>> Hello Vijay,
>>>
>>> On 03/03/2015 03:55, Vijay Kilari wrote:
>>>>
>>>>
>>>> On Mon, Mar 2, 2015 at 6:49 PM, Julien Grall <julien.grall@linaro.org>
>>>> wrote:
>>>>>
>>>>>
>>>>> On 02/03/15 12:30, vijay.kilari@gmail.com wrote:
>>>>>>
>>>>>>
>>>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>>>
>>>>>> Add ITS support for arm. Following major features
>>>>>> are supported
>>>>>>    - GICv3 ITS support for arm64 platform
>>>>>>    - Supports only single ITS node
>>>>>
>>>>>
>>>>>
>>>>> Why only one ITS node supported? I though Cavium was using 2 ITS...
>>>>
>>>>
>>>>
>>>> I will update for 2 ITS nodes later when NUMA is supported
>>>
>>>
>>>
>>> Why do you speak about NUMA? AFAICT, there is no requirement to support
>>> NUMA
>>> for having multiple ITS...
>>>
>>> With multiple ITS support, your vITS emulation will likely heavily
>>> change.
>>> So it would be nice to have this support as soon as possible.
>>
>>
>> Incremental changes (as separate patch series)
>> would be more meaningful. I will have a look at it
>> and if possible I will incorporate in next series
>
>
> It doesn't make sense to not support multiple ITS from the beginning.
>
> FWIW, your code is based on the Linux driver which support multiple ITS. So
> why did you drop this support?
>
> Anyway, I'm pretty sure you will have to rework the vITS with the support of
> multiple ITS... Having a separate patch means more work for all of us: more
> series and more review.
>

The changes that I envisage for supporting Multiple ITS is
  - Generate as many number of ITS dt nodes for Dom0 that host DT contains.
  - For DomU always generate only one ITS node
  - vITS will register MMIO handlers for all physical ITS of Dom0, but
vITS will only have
    one VITS structure per domain. The limitation with this approach
is that all vITS requests are
    serialized even though there are more than one physical ITS. But
this approach makes
    implementation simple.
 - The right Physical ITS node command queue is chosen based on device
id in the ITS commands.
   However few commands like MAPC, SYNC & INVALL does not have device
id. These commands
   needs special handling by either consume in vITS or send based on
Collection and Target address mapped.

Regards
Vijay

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-13  4:48           ` Vijay Kilari
@ 2015-03-13 10:13             ` Julien Grall
  2015-03-16 10:30               ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-13 10:13 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hi Vijay,

On 13/03/2015 04:48, Vijay Kilari wrote:
> The changes that I envisage for supporting Multiple ITS is
>    - Generate as many number of ITS dt nodes for Dom0 that host DT contains.
>    - For DomU always generate only one ITS node
>    - vITS will register MMIO handlers for all physical ITS of Dom0, but
> vITS will only have
>      one VITS structure per domain. The limitation with this approach
> is that all vITS requests are
>      serialized even though there are more than one physical ITS. But
> this approach makes
>      implementation simple.

Each vITS will have his own command queue... How do you plan to handle 
it with only a single structure?

Can you provide an idea what the structure will look like?

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-02 12:30 ` [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux vijay.kilari
@ 2015-03-13 10:24   ` Julien Grall
  2015-03-13 10:35     ` Julien Grall
  0 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-13 10:24 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar, manish.jaggi

Hello Vijay,

On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>
> This is actual GICv3 ITS driver from linux.
> No xen related changes are made and is not compiled.
>
> This helps to import any issues found in linux

Can you provide the commit ID you used to pick the file?

AFAICT there is at least one bug fix in upstream which may be necessary 
for us [1]

[1] c848126734e8621e81659d819922b20d93a2aa6d

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-13 10:24   ` Julien Grall
@ 2015-03-13 10:35     ` Julien Grall
  2015-03-16  9:55       ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-13 10:35 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar, manish.jaggi



On 13/03/2015 10:24, Julien Grall wrote:
> Hello Vijay,
>
> On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>
>> This is actual GICv3 ITS driver from linux.
>> No xen related changes are made and is not compiled.
>>
>> This helps to import any issues found in linux
>
> Can you provide the commit ID you used to pick the file?
>
> AFAICT there is at least one bug fix in upstream which may be necessary
> for us [1]
>
> [1] c848126734e8621e81659d819922b20d93a2aa6d

BTW this is not even a copy from Linux. You replaced all the hard tab by 
space...

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen
  2015-03-02 12:30 ` [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen vijay.kilari
@ 2015-03-13 11:46   ` Julien Grall
  2015-03-16 14:06     ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-13 11:46 UTC (permalink / raw)
  To: vijay.kilari, Ian.Campbell, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, vijaya.kumar, manish.jaggi

Hello Vijay,

On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
> @@ -228,10 +242,10 @@ static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,
>                                                    struct its_cmd_desc *desc)
>   {
>       unsigned long itt_addr;
> -    u8 size = max(order_base_2(desc->its_mapd_cmd.dev->nr_ites), 1);
> +    u8 size = max(fls(desc->its_mapd_cmd.dev->nr_ites) - 1, 1);

You may want to give a look to get_count_order.

>
> -    itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
> -    itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
> +    itt_addr = __pa(desc->its_mapd_cmd.dev->itt);
> +    itt_addr = ((itt_addr) + (ITS_ITT_ALIGN - 1)) & ~(ITS_ITT_ALIGN - 1);

You can use ROUNDUP.

[..]

> @@ -343,17 +357,23 @@ static int its_queue_full(struct its_node *its)
>   static struct its_cmd_block *its_allocate_entry(struct its_node *its)
>   {
>       struct its_cmd_block *cmd;
> -    u32 count = 1000000;    /* 1s! */
> +    bool_t timeout = 0;
> +    s_time_t deadline = NOW() + MILLISECS(1000);
>
>       while (its_queue_full(its)) {
> -        count--;
> -        if (!count) {
> -            pr_err_ratelimited("ITS queue not draining\n");
> -            return NULL;
> +       if ( NOW() > deadline )
> +        {
> +            timeout = 1;
> +            break;
>           }
>           cpu_relax();
>           udelay(1);
>       }
> +    if ( timeout )
> +    {
> +        its_err("ITS queue not draining\n");
> +        return NULL;
> +    }

Why do you need to modify the loop? It looks like to me it will work Xen 
too.

>       cmd = its->cmd_write++;
>
> @@ -380,7 +400,7 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
>        * the ITS.
>        */
>       if (its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING)
> -        __flush_dcache_area(cmd, sizeof(*cmd));
> +        clean_dcache_va_range(cmd, sizeof(*cmd));

__flush_dcache_area perform a clean & invalidate while 
clean_dcache_va_range only clean.

You may want to use clean_and_invalidate_va_range

[..]

> @@ -390,7 +410,8 @@ static void its_wait_for_range_completion(struct its_node *its,
>                                             struct its_cmd_block *to)
>   {
>       u64 rd_idx, from_idx, to_idx;
> -    u32 count = 1000000;    /* 1s! */
> +    bool_t timeout = 0;
> +    s_time_t deadline = NOW() + MILLISECS(1000);
>
>       from_idx = its_cmd_ptr_to_offset(its, from);
>       to_idx = its_cmd_ptr_to_offset(its, to);
> @@ -400,14 +421,16 @@ static void its_wait_for_range_completion(struct its_node *its,
>           if (rd_idx >= to_idx || rd_idx < from_idx)
>               break;
>
> -        count--;
> -        if (!count) {
> -            pr_err_ratelimited("ITS queue timeout\n");
> -            return;
> +        if ( NOW() > deadline )
> +        {
> +            timeout = 1;
> +            break;
>           }
>           cpu_relax();
>           udelay(1);
>       }
> +    if ( timeout )
> +        printk("ITS queue timeout\n");
>   }

Same question for the loop.

[..]

>   /*
> - * irqchip functions - assumes MSI, mostly.
> - */
> -
> -static void lpi_set_config(struct its_device *its_dev, u32 hwirq,
> -               u32 id, int enable)
> -{
> -    u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192;
> -
> -    if (enable)
> -        *cfg |= LPI_PROP_ENABLED;
> -    else
> -        *cfg &= ~LPI_PROP_ENABLED;
> -
> -    /*
> -     * Make the above write visible to the redistributors.
> -     * And yes, we're flushing exactly: One. Single. Byte.
> -     * Humpf...
> -     */
> -    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
> -        __flush_dcache_area(cfg, sizeof(*cfg));
> -    else
> -        dsb(ishst);
> -    its_send_inv(its_dev, id);
> -}
> -
> -static inline u16 its_msi_get_entry_nr(struct msi_desc *desc)
> -{
> -    return desc->msi_attrib.entry_nr;
> -}
> -
> -static void its_mask_irq(struct irq_data *d)
> -{
> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
> -    u32 id;
> -
> -    /* If MSI, propagate the mask to the RC */
> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
> -        id = its_msi_get_entry_nr(d->msi_desc);
> -        mask_msi_irq(d);
> -    } else {
> -        id = d->hwirq;
> -    }
> -
> -    lpi_set_config(its_dev, d->hwirq, id, 0);
> -}
> -
> -static void its_unmask_irq(struct irq_data *d)
> -{
> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
> -    u32 id;
> -
> -    /* If MSI, propagate the unmask to the RC */
> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
> -        id = its_msi_get_entry_nr(d->msi_desc);
> -        unmask_msi_irq(d);
> -    } else {
> -        id = d->hwirq;
> -    }
> -
> -    lpi_set_config(its_dev, d->hwirq, id, 1);
> -}
> -
> -static void its_eoi_irq(struct irq_data *d)
> -{
> -    gic_write_eoir(d->hwirq);
> -}
> -
> -static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
> -                            bool force)
> -{
> -    unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
> -    struct its_collection *target_col;
> -    u32 id;
> -
> -    if (cpu >= nr_cpu_ids)
> -        return -EINVAL;
> -
> -    target_col = &its_dev->its->collections[cpu];
> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc)
> -        id = its_msi_get_entry_nr(d->msi_desc);
> -    else
> -        id = d->hwirq;
> -    its_send_movi(its_dev, target_col, id);
> -    its_dev->collection = target_col;
> -
> -    return IRQ_SET_MASK_OK;
> -}
> -
> -static struct irq_chip its_irq_chip = {
> -    .name            = "ITS",
> -    .irq_mask        = its_mask_irq,
> -    .irq_unmask        = its_unmask_irq,
> -    .irq_eoi        = its_eoi_irq,
> -    .irq_set_affinity    = its_set_affinity,
> -};
> -

Most of those callbacks seems useful to me. Why did you drop them?

[..]

> -static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)
> +static unsigned long *its_lpi_alloc_chunks(int nr_irq, int *base, int *nr_ids)
>   {
>       unsigned long *bitmap = NULL;
>       int chunk_id;
>       int nr_chunks;
>       int i;
>
> -    nr_chunks = DIV_ROUND_UP(nr_irqs, IRQS_PER_CHUNK);
> +    nr_chunks = DIV_ROUND_UP(nr_irq, IRQS_PER_CHUNK);
>
>       spin_lock(&lpi_lock);
>
>       do {
> -        chunk_id = bitmap_find_next_zero_area(lpi_bitmap, lpi_chunks,
> -                                              0, nr_chunks, 0);
> +        chunk_id = find_next_zero_bit(lpi_bitmap, lpi_chunks, 0);

This is not the same. bitmap_find_next_zero_area looks for a contiguous 
region of nr_chunks while find_next_zero_bit looks for the first 0 bit.

[..]

>   /*
> @@ -732,31 +654,28 @@ static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
>   /*
>    * This is how many bits of ID we need, including the useless ones.
>    */
> -#define LPI_NRBITS        ilog2(LPI_PROPBASE_SZ + SZ_8K)
> +#define LPI_NRBITS        (fls(LPI_PROPBASE_SZ + SZ_8K) - 1)
>
> -#define LPI_PROP_DEFAULT_PRIO    0xa0
> +#define LPI_PROP_DEFAULT_PRIO    0xa2

It's more than a compilation fix...

>   static int __init its_alloc_lpi_tables(void)
>   {
> -    phys_addr_t paddr;
> +    gic_rdists->prop_page = alloc_xenheap_pages(get_order_from_bytes(LPI_PROPBASE_SZ), 0);
>
> -    gic_rdists->prop_page = alloc_pages(GFP_NOWAIT,
> -                       get_order(LPI_PROPBASE_SZ));
>       if (!gic_rdists->prop_page) {
> -        pr_err("Failed to allocate PROPBASE\n");
> +        its_err("Failed to allocate PROPBASE\n");
>           return -ENOMEM;
>       }
>
> -    paddr = page_to_phys(gic_rdists->prop_page);
> -    pr_info("GIC: using LPI property table @%pa\n", &paddr);
> +    its_info("GIC: using LPI property table @%pa\n", gic_rdists->prop_page);
>
>       /* Priority 0xa0, Group-1, disabled */
> -    memset(page_address(gic_rdists->prop_page),
> +    memset(gic_rdists->prop_page,
>              LPI_PROP_DEFAULT_PRIO | LPI_PROP_GROUP1,
>              LPI_PROPBASE_SZ);
>
>       /* Make sure the GIC will observe the written configuration */
> -    __flush_dcache_area(page_address(gic_rdists->prop_page), LPI_PROPBASE_SZ);
> +    clean_dcache_va_range(gic_rdists->prop_page, LPI_PROPBASE_SZ);

Ditto for __flush_dcache_area

[..]

> @@ -806,17 +725,18 @@ static int its_alloc_tables(struct its_node *its)
>           if (type == GITS_BASER_TYPE_NONE)
>               continue;
>
> -        base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(max_ittsize));
> +        base = alloc_xenheap_pages(get_order_from_bytes(max_ittsize), 0);
>           if (!base) {
>               err = -ENOMEM;
>               goto out_free;
>           }
> -
> +        memset(base, 0, max_ittsize);
> +        clear_page(base);

Why do you do both? memset should be enough. Although, you may need to 
align max_ittsize.

[..]

> @@ -909,32 +827,30 @@ static int its_alloc_collections(struct its_node *its)
>   static void its_cpu_init_lpis(void)
>   {
>       void __iomem *rbase = gic_data_rdist_rd_base();
> -    struct page *pend_page;
> +    void *pend_page;
>       u64 val, tmp;
>
>       /* If we didn't allocate the pending table yet, do it now */
> -    pend_page = gic_data_rdist()->pend_page;
> +    pend_page = gic_data_rdist().pend_page;

It would make sense to have gic_data_rdist returning a pointer. That 
would avoid a such change.

[..]

> +        memset(pend_page, 0, max(LPI_PENDBASE_SZ, SZ_64K));
>           /* Make sure the GIC will observe the zero-ed page */
> -        __flush_dcache_area(page_address(pend_page), LPI_PENDBASE_SZ);
> +        clean_dcache_va_range(pend_page, LPI_PENDBASE_SZ);

Ditto for clean_dcache_va_range

[..]

>
> -static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
> -                                            int nvecs)
> +/* TODO: Removed static for compilation */

It's a bit strange to add a TODO but not on the same other changes. See 
its_lpi_free for instance.

[..]

> -static int its_alloc_device_irq(struct its_device *dev, u32 id,
> -                                int *hwirq, unsigned int *irq)
> +/* TODO: Removed static for compilation */
> +int its_alloc_device_irq(struct its_device *dev, u32 id,
> +                         int *hwirq, unsigned int *irq)
>   {
>       int idx;
>
> @@ -1101,9 +1019,6 @@ static int its_alloc_device_irq(struct its_device *dev, u32 id,
>           return -ENOSPC;
>
>       *hwirq = dev->lpi_base + idx;
> -    *irq = irq_create_mapping(lpi_domain, *hwirq);
> -    if (!*irq)
> -        return -ENOSPC;    /* Don't kill the device, though */

With this change *irq is not set at all. Do you plan to fix it later?

>       set_bit(idx, dev->lpi_map);
>
> @@ -1113,134 +1028,52 @@ static int its_alloc_device_irq(struct its_device *dev, u32 id,
>       return 0;
>   }
>
> -
> -
> -static int its_msi_get_vec_count(struct pci_dev *pdev, struct msi_desc *desc)
> -{
> -#ifdef CONFIG_PCI_MSI
> -    if (desc->msi_attrib.is_msix)
> -        return pci_msix_vec_count(pdev);
> -    else
> -        return pci_msi_vec_count(pdev);
> -#else
> -    return -EINVAL;
> -#endif
> -}
> -
> -int pci_requester_id(struct pci_dev *dev);
> -static int its_msi_setup_irq(struct msi_chip *chip,
> -                             struct pci_dev *pdev,
> -                             struct msi_desc *desc)
> -{
> -    struct its_node *its = container_of(chip, struct its_node, msi_chip);
> -    struct its_device *its_dev;
> -    struct msi_msg msg;
> -    unsigned int irq;
> -    u64 addr;
> -    int hwirq;
> -    int err;
> -    u32 dev_id = pci_requester_id(pdev);
> -    u32 vec_nr;
> -
> -    its_dev = its_find_device(its, dev_id);
> -    if (!its_dev) {
> -        int nvec = its_msi_get_vec_count(pdev, desc);
> -        if (WARN_ON(nvec <= 0))
> -            return nvec;
> -        its_dev = its_create_device(its, dev_id, nvec);
> -    }
> -    if (!its_dev)
> -        return -ENOMEM;
> -    vec_nr = its_msi_get_entry_nr(desc);
> -    err = its_alloc_device_irq(its_dev, vec_nr, &hwirq, &irq);
> -    if (err)
> -        return err;
> -
> -    irq_set_msi_desc(irq, desc);
> -    irq_set_handler_data(irq, its_dev);
> -
> -    addr = its->phys_base + GITS_TRANSLATER;
> -
> -    msg.address_lo        = (u32)addr;
> -    msg.address_hi        = (u32)(addr >> 32);
> -    msg.data        = vec_nr;
> -
> -    write_msi_msg(irq, &msg);
> -    return 0;
> -}
> -
> -static void its_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
> -{
> -    struct irq_data *d = irq_get_irq_data(irq);
> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
> -
> -    BUG_ON(d->hwirq < its_dev->lpi_base ||        /* OMG! */
> -           d->hwirq > (its_dev->lpi_base + its_dev->nr_lpis));
> -
> -    /* Stop the delivery of interrupts */
> -    its_send_discard(its_dev, its_msi_get_entry_nr(d->msi_desc));
> -
> -    /* Mark interrupt index as unused, and clear the mapping */
> -    clear_bit(d->hwirq - its_dev->lpi_base, its_dev->lpi_map);
> -    irq_dispose_mapping(irq);
> -
> -    /* If all interrupts have been freed, start mopping the floor */
> -    if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
> -        its_lpi_free(its_dev->lpi_map,
> -                     its_dev->lpi_base,
> -                     its_dev->nr_lpis);
> -
> -        /* Unmap device/itt */
> -        its_send_mapd(its_dev, 0);
> -        its_free_device(its_dev);
> -    }
> -}
> -

Those 2 functions seems useful for me. Why did you drop them?

> -static int its_probe(struct device_node *node)
> +static int its_probe(struct dt_device_node *node)
>   {
> -    struct resource res;
> +    paddr_t its_addr, its_size;
>       struct its_node *its;
>       void __iomem *its_base;
>       u32 val;
>       u64 baser, tmp;
>       int err;
>
> -    err = of_address_to_resource(node, 0, &res);
> -    if (err) {
> -        pr_warn("%s: no regs?\n", node->full_name);
> +    err = dt_device_get_address(node, 0, &its_addr, &its_size);
> +    if ( err || !its_addr )

Why the second check (!its_addr)?

> +    {
> +        its_warn("%s: cannot find GIC-ITS\n", node->full_name);
>           return -ENXIO;
>       }
>
> -    its_base = ioremap(res.start, resource_size(&res));
> -    if (!its_base) {
> -        pr_warn("%s: unable to map registers\n", node->full_name);
> +    its_base = ioremap_nocache(its_addr, its_size);
> +    if ( !its_base)
> +    {

Please keep the Linux coding style.

[..]

> @@ -1255,19 +1088,19 @@ static int its_probe(struct device_node *node)

[..]

>       writeq_relaxed(baser, its->base + GITS_CBASER);
>       tmp = readq_relaxed(its->base + GITS_CBASER);
> -/*    writeq_relaxed(0, its->base + GITS_CWRITER); */
> +    writeq_relaxed(0, its->base + GITS_CWRITER);

Care to explain why it was commented on the previous patch and you 
uncomment here?

[..]

>   out_free_tables:
>       its_free_tables(its);
>   out_free_cmd:
> -    kfree(its->cmd_base);
> +    xfree(its->cmd_base);
>   out_free_its:
> -    kfree(its);
> +    xfree(its);
>   out_unmap:
> -    iounmap(its_base);
> -    pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
> +    //TODO: no call for iounmap in xen?

The function exists since 2012 in xen/vmap.h ...

[..]

> -static struct of_device_id its_device_id[] = {
> -    {    .compatible    = "arm,gic-v3-its",    },
> -    {},
> -};
> -
> -struct irq_chip *its_init(struct device_node *node, struct rdists *rdists,
> -                          struct irq_domain *domain)
> +int its_init(struct dt_device_node *node, struct rdist_prop *rdists)
>   {
> -    struct device_node *np;
> +    static const struct dt_device_match its_device_ids[] __initconst =
> +    {
> +        DT_MATCH_COMPATIBLE("arm,gic-v3-its"),
> +        { /* sentinel */ },
> +    };

Just modifing the type of the its_device_id would have been work too.

s/of_device_id/dt_device_match/

> +    struct dt_device_node *np = NULL;
>
> -    for (np = of_find_matching_node(node, its_device_id); np;
> -         np = of_find_matching_node(np, its_device_id)) {
> -        its_probe(np);
> +    while ( (np = dt_find_matching_node(np, its_device_ids)) )
> +    {
> +        if ( !dt_find_property(np, "msi-controller", NULL) )
> +            continue;
> +
> +        if ( dt_get_parent(np) )
> +            break;

Linux doesn't do those check, why do you need them?

[..]

> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index 47452ca..5c35ac5 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -63,6 +63,7 @@ static struct gic_info gicv3_info;
>
>   /* per-cpu re-distributor base */
>   static DEFINE_PER_CPU(void __iomem*, rbase);
> +DEFINE_PER_CPU(struct rdist, rdist);

It would have been better to create a separate patch before in order to 
implment rdist correctly.

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-13 10:35     ` Julien Grall
@ 2015-03-16  9:55       ` Vijay Kilari
  2015-03-16 10:12         ` Stefano Stabellini
  2015-03-16 13:15         ` Julien Grall
  0 siblings, 2 replies; 59+ messages in thread
From: Vijay Kilari @ 2015-03-16  9:55 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Fri, Mar 13, 2015 at 4:05 PM, Julien Grall <julien.grall@linaro.org> wrote:
>
>
> On 13/03/2015 10:24, Julien Grall wrote:
>>
>> Hello Vijay,
>>
>> On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
>>>
>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>
>>> This is actual GICv3 ITS driver from linux.
>>> No xen related changes are made and is not compiled.
>>>
>>> This helps to import any issues found in linux
>>
>>
>> Can you provide the commit ID you used to pick the file?
>>
>> AFAICT there is at least one bug fix in upstream which may be necessary
>> for us [1]
>>
>> [1] c848126734e8621e81659d819922b20d93a2aa6d

This patch has changes in its_create_device() is not used.

BTW, I am using 3.18 kernel. Can I pull latest ITS driver from 4.0 and
use it?

>
>
> BTW this is not even a copy from Linux. You replaced all the hard tab by
> space...

Yes, I replaced tabs. Whats the ways of copying linux driver to Xen.
Should we keep and maintain coding style as well?

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

* Re: [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-16  9:55       ` Vijay Kilari
@ 2015-03-16 10:12         ` Stefano Stabellini
  2015-03-16 13:04           ` Julien Grall
  2015-03-16 13:15         ` Julien Grall
  1 sibling, 1 reply; 59+ messages in thread
From: Stefano Stabellini @ 2015-03-16 10:12 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Julien Grall, Tim Deegan, xen-devel, Stefano Stabellini,
	manish.jaggi

On Mon, 16 Mar 2015, Vijay Kilari wrote:
> On Fri, Mar 13, 2015 at 4:05 PM, Julien Grall <julien.grall@linaro.org> wrote:
> >
> >
> > On 13/03/2015 10:24, Julien Grall wrote:
> >>
> >> Hello Vijay,
> >>
> >> On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
> >>>
> >>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
> >>>
> >>> This is actual GICv3 ITS driver from linux.
> >>> No xen related changes are made and is not compiled.
> >>>
> >>> This helps to import any issues found in linux
> >>
> >>
> >> Can you provide the commit ID you used to pick the file?
> >>
> >> AFAICT there is at least one bug fix in upstream which may be necessary
> >> for us [1]
> >>
> >> [1] c848126734e8621e81659d819922b20d93a2aa6d
> 
> This patch has changes in its_create_device() is not used.
> 
> BTW, I am using 3.18 kernel. Can I pull latest ITS driver from 4.0 and
> use it?

Yep


> >
> > BTW this is not even a copy from Linux. You replaced all the hard tab by
> > space...
> 
> Yes, I replaced tabs. Whats the ways of copying linux driver to Xen.
> Should we keep and maintain coding style as well?

If it is the Linux driver you are importing, then it might be worth
trying to keep it as close to the original as possible so that it won't
be too hard to update in the future. Like Julien has done for the SMMU
driver.

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

* Re: [RFC PATCH 00/19] xen/arm: Add ITS support
  2015-03-13 10:13             ` Julien Grall
@ 2015-03-16 10:30               ` Vijay Kilari
  0 siblings, 0 replies; 59+ messages in thread
From: Vijay Kilari @ 2015-03-16 10:30 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Fri, Mar 13, 2015 at 3:43 PM, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Vijay,
>
> On 13/03/2015 04:48, Vijay Kilari wrote:
>>
>> The changes that I envisage for supporting Multiple ITS is
>>    - Generate as many number of ITS dt nodes for Dom0 that host DT
>> contains.
>>    - For DomU always generate only one ITS node
>>    - vITS will register MMIO handlers for all physical ITS of Dom0, but
>> vITS will only have
>>      one VITS structure per domain. The limitation with this approach
>> is that all vITS requests are
>>      serialized even though there are more than one physical ITS. But
>> this approach makes
>>      implementation simple.
>
>
> Each vITS will have his own command queue... How do you plan to handle it
> with only a single structure?

Yes, I agree with single structure we could not maintain two commad queues

>
> Can you provide an idea what the structure will look like?

Below is the sample structures with description. I will send patch series

struct cid_mapping
{
    /* Number of collections mapped */
    uint8_t nr_cid;
    /* XXX: assume one collection id per vcpu. can set to MAX_VCPUS? */
    /* Virtual collection id */
    uint8_t vcid[32];
    /* Physical collection id */
    uint8_t pcid[32];
    /* Virtual target address of this collection id */
    uint64_t vta[32];
};

struct its_node;

/* Per domain per physical ITS, virtual ITS struct */
struct vgic_its
{
   spinlock_t lock;
   /* Emulation of BASER */
   paddr_t baser[8];
   /* Command queue base */
   paddr_t cmd_base;
   /* Command queue write pointer */
   paddr_t cmd_write;
   /* Command queue write saved pointer */
   paddr_t cmd_write_save;
   /* Command queue read pointer */
   paddr_t cmd_read;
   /* Command queue size */
   unsigned long cmd_qsize;
   /* ITS mmio physical base */
   paddr_t phys_base;
   /* ITS mmio physical size */
   unsigned long phys_size;
   /* gicr ctrl register */
   uint32_t ctrl;
   /* Virtual to Physical Collection id mapping */
   struct cid_mapping cid_map;
};

struct vgic_lpi_conf
{
   /* LPI propbase */
   paddr_t propbase;
   /* percpu pendbase */
   paddr_t pendbase[MAX_VIRT_CPUS];
   /* Virtual LPI property table */
   void * prop_page;
};

/* ITS device structure */
struct vits_device
{
    struct list_head entry;
    /* Virtual ITS node */
    struct vgic_its *vits;
    /* ITS physical node */
    struct its_node *its;
    /* Collection assigned */
    struct its_collection *collection;
    /* Device id */
    uint32_t  dev_id;
    /* ITT address */
    paddr_t itt_addr;
    /* ITT size */
    unsigned long itt_size;
    /* LPIs assigned to device */
    struct list_head hwirq_list;
};

asm-arm/domain.h


struct vgic_its *vits;
struct vgic_lpi_conf *lpi_conf;
struct vits_device {
    spinlock_t lock;
    struct list_head dev_List;
} vits_devs;

Regards
Vijay

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

* Re: [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-16 10:12         ` Stefano Stabellini
@ 2015-03-16 13:04           ` Julien Grall
  0 siblings, 0 replies; 59+ messages in thread
From: Julien Grall @ 2015-03-16 13:04 UTC (permalink / raw)
  To: Stefano Stabellini, Vijay Kilari
  Cc: Ian Campbell, Prasun Kapoor, Vijaya Kumar K, Tim Deegan,
	xen-devel, Stefano Stabellini, manish.jaggi

On 16/03/15 10:12, Stefano Stabellini wrote:
>>> BTW this is not even a copy from Linux. You replaced all the hard tab by
>>> space...
>>
>> Yes, I replaced tabs. Whats the ways of copying linux driver to Xen.
>> Should we keep and maintain coding style as well?
> 
> If it is the Linux driver you are importing, then it might be worth
> trying to keep it as close to the original as possible so that it won't
> be too hard to update in the future. Like Julien has done for the SMMU
> driver.

Given all the changes made in the driver afterwards, I don't think it
would possible to backport patch from Linux.

But at least it would help to see the difference during the review of
this series.

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-16  9:55       ` Vijay Kilari
  2015-03-16 10:12         ` Stefano Stabellini
@ 2015-03-16 13:15         ` Julien Grall
  2015-03-16 13:32           ` Vijay Kilari
  1 sibling, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-16 13:15 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hi Vijay,

On 16/03/15 09:55, Vijay Kilari wrote:
> On Fri, Mar 13, 2015 at 4:05 PM, Julien Grall <julien.grall@linaro.org> wrote:
>>
>>
>> On 13/03/2015 10:24, Julien Grall wrote:
>>>
>>> Hello Vijay,
>>>
>>> On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
>>>>
>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>
>>>> This is actual GICv3 ITS driver from linux.
>>>> No xen related changes are made and is not compiled.
>>>>
>>>> This helps to import any issues found in linux
>>>
>>>
>>> Can you provide the commit ID you used to pick the file?
>>>
>>> AFAICT there is at least one bug fix in upstream which may be necessary
>>> for us [1]
>>>
>>> [1] c848126734e8621e81659d819922b20d93a2aa6d
> 
> This patch has changes in its_create_device() is not used.

But you are modifying its_create_device in patch #2 in order to make the
code compile.

It's really hard to follow what is necessary or not from the real driver.

Looking to this function, it seems to be very useful in order to track
which ITS is associated to the device.

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux
  2015-03-16 13:15         ` Julien Grall
@ 2015-03-16 13:32           ` Vijay Kilari
  0 siblings, 0 replies; 59+ messages in thread
From: Vijay Kilari @ 2015-03-16 13:32 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Mon, Mar 16, 2015 at 6:45 PM, Julien Grall <julien.grall@linaro.org> wrote:
> Hi Vijay,
>
> On 16/03/15 09:55, Vijay Kilari wrote:
>> On Fri, Mar 13, 2015 at 4:05 PM, Julien Grall <julien.grall@linaro.org> wrote:
>>>
>>>
>>> On 13/03/2015 10:24, Julien Grall wrote:
>>>>
>>>> Hello Vijay,
>>>>
>>>> On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
>>>>>
>>>>> From: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
>>>>>
>>>>> This is actual GICv3 ITS driver from linux.
>>>>> No xen related changes are made and is not compiled.
>>>>>
>>>>> This helps to import any issues found in linux
>>>>
>>>>
>>>> Can you provide the commit ID you used to pick the file?
>>>>
>>>> AFAICT there is at least one bug fix in upstream which may be necessary
>>>> for us [1]
>>>>
>>>> [1] c848126734e8621e81659d819922b20d93a2aa6d
>>
>> This patch has changes in its_create_device() is not used.
>
> But you are modifying its_create_device in patch #2 in order to make the
> code compile.
>
> It's really hard to follow what is necessary or not from the real driver.
>
> Looking to this function, it seems to be very useful in order to track
> which ITS is associated to the device.

Just to make it compile I kept this function in patch#2
In patch#4 "xen/arm: its: Remove unused code in ITS driver"
this code is removed.

First we can remove unused code and later make it compile in next patch.
But that make changes are not incremental fashion.

The vits_its_add_device() in vITS driver will track the devices
added to the domain.

Regards
Vijay

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

* Re: [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen
  2015-03-13 11:46   ` Julien Grall
@ 2015-03-16 14:06     ` Vijay Kilari
  2015-03-16 14:20       ` Julien Grall
  0 siblings, 1 reply; 59+ messages in thread
From: Vijay Kilari @ 2015-03-16 14:06 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

Hi Julien,

On Fri, Mar 13, 2015 at 5:16 PM, Julien Grall <julien.grall@linaro.org> wrote:
> Hello Vijay,
>
> On 02/03/2015 12:30, vijay.kilari@gmail.com wrote:
>>
>> @@ -228,10 +242,10 @@ static struct its_collection
>> *its_build_mapd_cmd(struct its_cmd_block *cmd,
>>                                                    struct its_cmd_desc
>> *desc)
>>   {
>>       unsigned long itt_addr;
>> -    u8 size = max(order_base_2(desc->its_mapd_cmd.dev->nr_ites), 1);
>> +    u8 size = max(fls(desc->its_mapd_cmd.dev->nr_ites) - 1, 1);
>
>
> You may want to give a look to get_count_order.
>
>>
>> -    itt_addr = virt_to_phys(desc->its_mapd_cmd.dev->itt);
>> -    itt_addr = ALIGN(itt_addr, ITS_ITT_ALIGN);
>> +    itt_addr = __pa(desc->its_mapd_cmd.dev->itt);
>> +    itt_addr = ((itt_addr) + (ITS_ITT_ALIGN - 1)) & ~(ITS_ITT_ALIGN - 1);
>
>
> You can use ROUNDUP.
>
> [..]
>
>> @@ -343,17 +357,23 @@ static int its_queue_full(struct its_node *its)
>>   static struct its_cmd_block *its_allocate_entry(struct its_node *its)
>>   {
>>       struct its_cmd_block *cmd;
>> -    u32 count = 1000000;    /* 1s! */
>> +    bool_t timeout = 0;
>> +    s_time_t deadline = NOW() + MILLISECS(1000);
>>
>>       while (its_queue_full(its)) {
>> -        count--;
>> -        if (!count) {
>> -            pr_err_ratelimited("ITS queue not draining\n");
>> -            return NULL;
>> +       if ( NOW() > deadline )
>> +        {
>> +            timeout = 1;
>> +            break;
>>           }
>>           cpu_relax();
>>           udelay(1);
>>       }
>> +    if ( timeout )
>> +    {
>> +        its_err("ITS queue not draining\n");
>> +        return NULL;
>> +    }
>
>
> Why do you need to modify the loop? It looks like to me it will work Xen
> too.

I remember we used similar approach for GICv3.

>
>>   /*
>> - * irqchip functions - assumes MSI, mostly.
>> - */
>> -
>> -static void lpi_set_config(struct its_device *its_dev, u32 hwirq,
>> -               u32 id, int enable)
>> -{
>> -    u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192;
>> -
>> -    if (enable)
>> -        *cfg |= LPI_PROP_ENABLED;
>> -    else
>> -        *cfg &= ~LPI_PROP_ENABLED;
>> -
>> -    /*
>> -     * Make the above write visible to the redistributors.
>> -     * And yes, we're flushing exactly: One. Single. Byte.
>> -     * Humpf...
>> -     */
>> -    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
>> -        __flush_dcache_area(cfg, sizeof(*cfg));
>> -    else
>> -        dsb(ishst);
>> -    its_send_inv(its_dev, id);
>> -}
>> -
>> -static inline u16 its_msi_get_entry_nr(struct msi_desc *desc)
>> -{
>> -    return desc->msi_attrib.entry_nr;
>> -}
>> -
>> -static void its_mask_irq(struct irq_data *d)
>> -{
>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>> -    u32 id;
>> -
>> -    /* If MSI, propagate the mask to the RC */
>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
>> -        id = its_msi_get_entry_nr(d->msi_desc);
>> -        mask_msi_irq(d);
>> -    } else {
>> -        id = d->hwirq;
>> -    }
>> -
>> -    lpi_set_config(its_dev, d->hwirq, id, 0);
>> -}
>> -
>> -static void its_unmask_irq(struct irq_data *d)
>> -{
>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>> -    u32 id;
>> -
>> -    /* If MSI, propagate the unmask to the RC */
>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
>> -        id = its_msi_get_entry_nr(d->msi_desc);
>> -        unmask_msi_irq(d);
>> -    } else {
>> -        id = d->hwirq;
>> -    }
>> -
>> -    lpi_set_config(its_dev, d->hwirq, id, 1);
>> -}
>> -
>> -static void its_eoi_irq(struct irq_data *d)
>> -{
>> -    gic_write_eoir(d->hwirq);
>> -}
>> -
>> -static int its_set_affinity(struct irq_data *d, const struct cpumask
>> *mask_val,
>> -                            bool force)
>> -{
>> -    unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>> -    struct its_collection *target_col;
>> -    u32 id;
>> -
>> -    if (cpu >= nr_cpu_ids)
>> -        return -EINVAL;
>> -
>> -    target_col = &its_dev->its->collections[cpu];
>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc)
>> -        id = its_msi_get_entry_nr(d->msi_desc);
>> -    else
>> -        id = d->hwirq;
>> -    its_send_movi(its_dev, target_col, id);
>> -    its_dev->collection = target_col;
>> -
>> -    return IRQ_SET_MASK_OK;
>> -}
>> -
>> -static struct irq_chip its_irq_chip = {
>> -    .name            = "ITS",
>> -    .irq_mask        = its_mask_irq,
>> -    .irq_unmask        = its_unmask_irq,
>> -    .irq_eoi        = its_eoi_irq,
>> -    .irq_set_affinity    = its_set_affinity,
>> -};
>> -
>
>
> Most of those callbacks seems useful to me. Why did you drop them?

There is no irq_chip in xen. So thought of removing in completely and
adding as separate patch



>>
>> -
>> -
>> -static int its_msi_get_vec_count(struct pci_dev *pdev, struct msi_desc
>> *desc)
>> -{
>> -#ifdef CONFIG_PCI_MSI
>> -    if (desc->msi_attrib.is_msix)
>> -        return pci_msix_vec_count(pdev);
>> -    else
>> -        return pci_msi_vec_count(pdev);
>> -#else
>> -    return -EINVAL;
>> -#endif
>> -}
>> -
>> -int pci_requester_id(struct pci_dev *dev);
>> -static int its_msi_setup_irq(struct msi_chip *chip,
>> -                             struct pci_dev *pdev,
>> -                             struct msi_desc *desc)
>> -{
>> -    struct its_node *its = container_of(chip, struct its_node, msi_chip);
>> -    struct its_device *its_dev;
>> -    struct msi_msg msg;
>> -    unsigned int irq;
>> -    u64 addr;
>> -    int hwirq;
>> -    int err;
>> -    u32 dev_id = pci_requester_id(pdev);
>> -    u32 vec_nr;
>> -
>> -    its_dev = its_find_device(its, dev_id);
>> -    if (!its_dev) {
>> -        int nvec = its_msi_get_vec_count(pdev, desc);
>> -        if (WARN_ON(nvec <= 0))
>> -            return nvec;
>> -        its_dev = its_create_device(its, dev_id, nvec);
>> -    }
>> -    if (!its_dev)
>> -        return -ENOMEM;
>> -    vec_nr = its_msi_get_entry_nr(desc);
>> -    err = its_alloc_device_irq(its_dev, vec_nr, &hwirq, &irq);
>> -    if (err)
>> -        return err;
>> -
>> -    irq_set_msi_desc(irq, desc);
>> -    irq_set_handler_data(irq, its_dev);
>> -
>> -    addr = its->phys_base + GITS_TRANSLATER;
>> -
>> -    msg.address_lo        = (u32)addr;
>> -    msg.address_hi        = (u32)(addr >> 32);
>> -    msg.data        = vec_nr;
>> -
>> -    write_msi_msg(irq, &msg);
>> -    return 0;
>> -}
>> -
>> -static void its_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
>> -{
>> -    struct irq_data *d = irq_get_irq_data(irq);
>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>> -
>> -    BUG_ON(d->hwirq < its_dev->lpi_base ||        /* OMG! */
>> -           d->hwirq > (its_dev->lpi_base + its_dev->nr_lpis));
>> -
>> -    /* Stop the delivery of interrupts */
>> -    its_send_discard(its_dev, its_msi_get_entry_nr(d->msi_desc));
>> -
>> -    /* Mark interrupt index as unused, and clear the mapping */
>> -    clear_bit(d->hwirq - its_dev->lpi_base, its_dev->lpi_map);
>> -    irq_dispose_mapping(irq);
>> -
>> -    /* If all interrupts have been freed, start mopping the floor */
>> -    if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
>> -        its_lpi_free(its_dev->lpi_map,
>> -                     its_dev->lpi_base,
>> -                     its_dev->nr_lpis);
>> -
>> -        /* Unmap device/itt */
>> -        its_send_mapd(its_dev, 0);
>> -        its_free_device(its_dev);
>> -    }
>> -}
>> -
>
>
> Those 2 functions seems useful for me. Why did you drop them?

These are callbacks registered for msi_chip in linux, Since we have removed
msi_chip from its_node structure, these functions are supposed to be removed.

Regards
Vijay

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

* Re: [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen
  2015-03-16 14:06     ` Vijay Kilari
@ 2015-03-16 14:20       ` Julien Grall
  2015-03-16 16:03         ` Vijay Kilari
  0 siblings, 1 reply; 59+ messages in thread
From: Julien Grall @ 2015-03-16 14:20 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On 16/03/15 14:06, Vijay Kilari wrote:
>>> @@ -343,17 +357,23 @@ static int its_queue_full(struct its_node *its)
>>>   static struct its_cmd_block *its_allocate_entry(struct its_node *its)
>>>   {
>>>       struct its_cmd_block *cmd;
>>> -    u32 count = 1000000;    /* 1s! */
>>> +    bool_t timeout = 0;
>>> +    s_time_t deadline = NOW() + MILLISECS(1000);
>>>
>>>       while (its_queue_full(its)) {
>>> -        count--;
>>> -        if (!count) {
>>> -            pr_err_ratelimited("ITS queue not draining\n");
>>> -            return NULL;
>>> +       if ( NOW() > deadline )
>>> +        {
>>> +            timeout = 1;
>>> +            break;
>>>           }
>>>           cpu_relax();
>>>           udelay(1);
>>>       }
>>> +    if ( timeout )
>>> +    {
>>> +        its_err("ITS queue not draining\n");
>>> +        return NULL;
>>> +    }
>>
>>
>> Why do you need to modify the loop? It looks like to me it will work Xen
>> too.
> 
> I remember we used similar approach for GICv3.

The GICv3 driver is not really imported from Linux... The loop solution
was suggested by Ian in order to avoid an infinite loop.

Anyway, that doesn't make a reason to change a valid code...

>>
>>>   /*
>>> - * irqchip functions - assumes MSI, mostly.
>>> - */
>>> -
>>> -static void lpi_set_config(struct its_device *its_dev, u32 hwirq,
>>> -               u32 id, int enable)
>>> -{
>>> -    u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192;
>>> -
>>> -    if (enable)
>>> -        *cfg |= LPI_PROP_ENABLED;
>>> -    else
>>> -        *cfg &= ~LPI_PROP_ENABLED;
>>> -
>>> -    /*
>>> -     * Make the above write visible to the redistributors.
>>> -     * And yes, we're flushing exactly: One. Single. Byte.
>>> -     * Humpf...
>>> -     */
>>> -    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
>>> -        __flush_dcache_area(cfg, sizeof(*cfg));
>>> -    else
>>> -        dsb(ishst);
>>> -    its_send_inv(its_dev, id);
>>> -}
>>> -
>>> -static inline u16 its_msi_get_entry_nr(struct msi_desc *desc)
>>> -{
>>> -    return desc->msi_attrib.entry_nr;
>>> -}
>>> -
>>> -static void its_mask_irq(struct irq_data *d)
>>> -{
>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>> -    u32 id;
>>> -
>>> -    /* If MSI, propagate the mask to the RC */
>>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
>>> -        id = its_msi_get_entry_nr(d->msi_desc);
>>> -        mask_msi_irq(d);
>>> -    } else {
>>> -        id = d->hwirq;
>>> -    }
>>> -
>>> -    lpi_set_config(its_dev, d->hwirq, id, 0);
>>> -}
>>> -
>>> -static void its_unmask_irq(struct irq_data *d)
>>> -{
>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>> -    u32 id;
>>> -
>>> -    /* If MSI, propagate the unmask to the RC */
>>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
>>> -        id = its_msi_get_entry_nr(d->msi_desc);
>>> -        unmask_msi_irq(d);
>>> -    } else {
>>> -        id = d->hwirq;
>>> -    }
>>> -
>>> -    lpi_set_config(its_dev, d->hwirq, id, 1);
>>> -}
>>> -
>>> -static void its_eoi_irq(struct irq_data *d)
>>> -{
>>> -    gic_write_eoir(d->hwirq);
>>> -}
>>> -
>>> -static int its_set_affinity(struct irq_data *d, const struct cpumask
>>> *mask_val,
>>> -                            bool force)
>>> -{
>>> -    unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>> -    struct its_collection *target_col;
>>> -    u32 id;
>>> -
>>> -    if (cpu >= nr_cpu_ids)
>>> -        return -EINVAL;
>>> -
>>> -    target_col = &its_dev->its->collections[cpu];
>>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc)
>>> -        id = its_msi_get_entry_nr(d->msi_desc);
>>> -    else
>>> -        id = d->hwirq;
>>> -    its_send_movi(its_dev, target_col, id);
>>> -    its_dev->collection = target_col;
>>> -
>>> -    return IRQ_SET_MASK_OK;
>>> -}
>>> -
>>> -static struct irq_chip its_irq_chip = {
>>> -    .name            = "ITS",
>>> -    .irq_mask        = its_mask_irq,
>>> -    .irq_unmask        = its_unmask_irq,
>>> -    .irq_eoi        = its_eoi_irq,
>>> -    .irq_set_affinity    = its_set_affinity,
>>> -};
>>> -
>>
>>
>> Most of those callbacks seems useful to me. Why did you drop them?
> 
> There is no irq_chip in xen. So thought of removing in completely and
> adding as separate patch

What the point to remove and re-add code later? Except making more
difficult to review.

If this code is valid please move in an #if 0/#endif

> 
>>>
>>> -
>>> -
>>> -static int its_msi_get_vec_count(struct pci_dev *pdev, struct msi_desc
>>> *desc)
>>> -{
>>> -#ifdef CONFIG_PCI_MSI
>>> -    if (desc->msi_attrib.is_msix)
>>> -        return pci_msix_vec_count(pdev);
>>> -    else
>>> -        return pci_msi_vec_count(pdev);
>>> -#else
>>> -    return -EINVAL;
>>> -#endif
>>> -}
>>> -
>>> -int pci_requester_id(struct pci_dev *dev);
>>> -static int its_msi_setup_irq(struct msi_chip *chip,
>>> -                             struct pci_dev *pdev,
>>> -                             struct msi_desc *desc)
>>> -{
>>> -    struct its_node *its = container_of(chip, struct its_node, msi_chip);
>>> -    struct its_device *its_dev;
>>> -    struct msi_msg msg;
>>> -    unsigned int irq;
>>> -    u64 addr;
>>> -    int hwirq;
>>> -    int err;
>>> -    u32 dev_id = pci_requester_id(pdev);
>>> -    u32 vec_nr;
>>> -
>>> -    its_dev = its_find_device(its, dev_id);
>>> -    if (!its_dev) {
>>> -        int nvec = its_msi_get_vec_count(pdev, desc);
>>> -        if (WARN_ON(nvec <= 0))
>>> -            return nvec;
>>> -        its_dev = its_create_device(its, dev_id, nvec);
>>> -    }
>>> -    if (!its_dev)
>>> -        return -ENOMEM;
>>> -    vec_nr = its_msi_get_entry_nr(desc);
>>> -    err = its_alloc_device_irq(its_dev, vec_nr, &hwirq, &irq);
>>> -    if (err)
>>> -        return err;
>>> -
>>> -    irq_set_msi_desc(irq, desc);
>>> -    irq_set_handler_data(irq, its_dev);
>>> -
>>> -    addr = its->phys_base + GITS_TRANSLATER;
>>> -
>>> -    msg.address_lo        = (u32)addr;
>>> -    msg.address_hi        = (u32)(addr >> 32);
>>> -    msg.data        = vec_nr;
>>> -
>>> -    write_msi_msg(irq, &msg);
>>> -    return 0;
>>> -}
>>> -
>>> -static void its_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
>>> -{
>>> -    struct irq_data *d = irq_get_irq_data(irq);
>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>> -
>>> -    BUG_ON(d->hwirq < its_dev->lpi_base ||        /* OMG! */
>>> -           d->hwirq > (its_dev->lpi_base + its_dev->nr_lpis));
>>> -
>>> -    /* Stop the delivery of interrupts */
>>> -    its_send_discard(its_dev, its_msi_get_entry_nr(d->msi_desc));
>>> -
>>> -    /* Mark interrupt index as unused, and clear the mapping */
>>> -    clear_bit(d->hwirq - its_dev->lpi_base, its_dev->lpi_map);
>>> -    irq_dispose_mapping(irq);
>>> -
>>> -    /* If all interrupts have been freed, start mopping the floor */
>>> -    if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
>>> -        its_lpi_free(its_dev->lpi_map,
>>> -                     its_dev->lpi_base,
>>> -                     its_dev->nr_lpis);
>>> -
>>> -        /* Unmap device/itt */
>>> -        its_send_mapd(its_dev, 0);
>>> -        its_free_device(its_dev);
>>> -    }
>>> -}
>>> -
>>
>>
>> Those 2 functions seems useful for me. Why did you drop them?
> 
> These are callbacks registered for msi_chip in linux, Since we have removed
> msi_chip from its_node structure, these functions are supposed to be removed.

How do you register/unregister MSI in this case?

Regards,

-- 
Julien Grall

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

* Re: [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen
  2015-03-16 14:20       ` Julien Grall
@ 2015-03-16 16:03         ` Vijay Kilari
  2015-03-16 16:18           ` Julien Grall
  0 siblings, 1 reply; 59+ messages in thread
From: Vijay Kilari @ 2015-03-16 16:03 UTC (permalink / raw)
  To: Julien Grall
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On Mon, Mar 16, 2015 at 7:50 PM, Julien Grall <julien.grall@linaro.org> wrote:
> On 16/03/15 14:06, Vijay Kilari wrote:
>>>> @@ -343,17 +357,23 @@ static int its_queue_full(struct its_node *its)
>>>>   static struct its_cmd_block *its_allocate_entry(struct its_node *its)
>>>>   {
>>>>       struct its_cmd_block *cmd;
>>>> -    u32 count = 1000000;    /* 1s! */
>>>> +    bool_t timeout = 0;
>>>> +    s_time_t deadline = NOW() + MILLISECS(1000);
>>>>
>>>>       while (its_queue_full(its)) {
>>>> -        count--;
>>>> -        if (!count) {
>>>> -            pr_err_ratelimited("ITS queue not draining\n");
>>>> -            return NULL;
>>>> +       if ( NOW() > deadline )
>>>> +        {
>>>> +            timeout = 1;
>>>> +            break;
>>>>           }
>>>>           cpu_relax();
>>>>           udelay(1);
>>>>       }
>>>> +    if ( timeout )
>>>> +    {
>>>> +        its_err("ITS queue not draining\n");
>>>> +        return NULL;
>>>> +    }
>>>
>>>
>>> Why do you need to modify the loop? It looks like to me it will work Xen
>>> too.
>>
>> I remember we used similar approach for GICv3.
>
> The GICv3 driver is not really imported from Linux... The loop solution
> was suggested by Ian in order to avoid an infinite loop.
>
> Anyway, that doesn't make a reason to change a valid code...
>
>>>
>>>>   /*
>>>> - * irqchip functions - assumes MSI, mostly.
>>>> - */
>>>> -
>>>> -static void lpi_set_config(struct its_device *its_dev, u32 hwirq,
>>>> -               u32 id, int enable)
>>>> -{
>>>> -    u8 *cfg = page_address(gic_rdists->prop_page) + hwirq - 8192;
>>>> -
>>>> -    if (enable)
>>>> -        *cfg |= LPI_PROP_ENABLED;
>>>> -    else
>>>> -        *cfg &= ~LPI_PROP_ENABLED;
>>>> -
>>>> -    /*
>>>> -     * Make the above write visible to the redistributors.
>>>> -     * And yes, we're flushing exactly: One. Single. Byte.
>>>> -     * Humpf...
>>>> -     */
>>>> -    if (gic_rdists->flags & RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING)
>>>> -        __flush_dcache_area(cfg, sizeof(*cfg));
>>>> -    else
>>>> -        dsb(ishst);
>>>> -    its_send_inv(its_dev, id);
>>>> -}
>>>> -
>>>> -static inline u16 its_msi_get_entry_nr(struct msi_desc *desc)
>>>> -{
>>>> -    return desc->msi_attrib.entry_nr;
>>>> -}
>>>> -
>>>> -static void its_mask_irq(struct irq_data *d)
>>>> -{
>>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>>> -    u32 id;
>>>> -
>>>> -    /* If MSI, propagate the mask to the RC */
>>>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
>>>> -        id = its_msi_get_entry_nr(d->msi_desc);
>>>> -        mask_msi_irq(d);
>>>> -    } else {
>>>> -        id = d->hwirq;
>>>> -    }
>>>> -
>>>> -    lpi_set_config(its_dev, d->hwirq, id, 0);
>>>> -}
>>>> -
>>>> -static void its_unmask_irq(struct irq_data *d)
>>>> -{
>>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>>> -    u32 id;
>>>> -
>>>> -    /* If MSI, propagate the unmask to the RC */
>>>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc) {
>>>> -        id = its_msi_get_entry_nr(d->msi_desc);
>>>> -        unmask_msi_irq(d);
>>>> -    } else {
>>>> -        id = d->hwirq;
>>>> -    }
>>>> -
>>>> -    lpi_set_config(its_dev, d->hwirq, id, 1);
>>>> -}
>>>> -
>>>> -static void its_eoi_irq(struct irq_data *d)
>>>> -{
>>>> -    gic_write_eoir(d->hwirq);
>>>> -}
>>>> -
>>>> -static int its_set_affinity(struct irq_data *d, const struct cpumask
>>>> *mask_val,
>>>> -                            bool force)
>>>> -{
>>>> -    unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
>>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>>> -    struct its_collection *target_col;
>>>> -    u32 id;
>>>> -
>>>> -    if (cpu >= nr_cpu_ids)
>>>> -        return -EINVAL;
>>>> -
>>>> -    target_col = &its_dev->its->collections[cpu];
>>>> -    if (IS_ENABLED(CONFIG_PCI_MSI) && d->msi_desc)
>>>> -        id = its_msi_get_entry_nr(d->msi_desc);
>>>> -    else
>>>> -        id = d->hwirq;
>>>> -    its_send_movi(its_dev, target_col, id);
>>>> -    its_dev->collection = target_col;
>>>> -
>>>> -    return IRQ_SET_MASK_OK;
>>>> -}
>>>> -
>>>> -static struct irq_chip its_irq_chip = {
>>>> -    .name            = "ITS",
>>>> -    .irq_mask        = its_mask_irq,
>>>> -    .irq_unmask        = its_unmask_irq,
>>>> -    .irq_eoi        = its_eoi_irq,
>>>> -    .irq_set_affinity    = its_set_affinity,
>>>> -};
>>>> -
>>>
>>>
>>> Most of those callbacks seems useful to me. Why did you drop them?
>>
>> There is no irq_chip in xen. So thought of removing in completely and
>> adding as separate patch
>
> What the point to remove and re-add code later? Except making more
> difficult to review.
>
> If this code is valid please move in an #if 0/#endif
>
>>
>>>>
>>>> -
>>>> -
>>>> -static int its_msi_get_vec_count(struct pci_dev *pdev, struct msi_desc
>>>> *desc)
>>>> -{
>>>> -#ifdef CONFIG_PCI_MSI
>>>> -    if (desc->msi_attrib.is_msix)
>>>> -        return pci_msix_vec_count(pdev);
>>>> -    else
>>>> -        return pci_msi_vec_count(pdev);
>>>> -#else
>>>> -    return -EINVAL;
>>>> -#endif
>>>> -}
>>>> -
>>>> -int pci_requester_id(struct pci_dev *dev);
>>>> -static int its_msi_setup_irq(struct msi_chip *chip,
>>>> -                             struct pci_dev *pdev,
>>>> -                             struct msi_desc *desc)
>>>> -{
>>>> -    struct its_node *its = container_of(chip, struct its_node, msi_chip);
>>>> -    struct its_device *its_dev;
>>>> -    struct msi_msg msg;
>>>> -    unsigned int irq;
>>>> -    u64 addr;
>>>> -    int hwirq;
>>>> -    int err;
>>>> -    u32 dev_id = pci_requester_id(pdev);
>>>> -    u32 vec_nr;
>>>> -
>>>> -    its_dev = its_find_device(its, dev_id);
>>>> -    if (!its_dev) {
>>>> -        int nvec = its_msi_get_vec_count(pdev, desc);
>>>> -        if (WARN_ON(nvec <= 0))
>>>> -            return nvec;
>>>> -        its_dev = its_create_device(its, dev_id, nvec);
>>>> -    }
>>>> -    if (!its_dev)
>>>> -        return -ENOMEM;
>>>> -    vec_nr = its_msi_get_entry_nr(desc);
>>>> -    err = its_alloc_device_irq(its_dev, vec_nr, &hwirq, &irq);
>>>> -    if (err)
>>>> -        return err;
>>>> -
>>>> -    irq_set_msi_desc(irq, desc);
>>>> -    irq_set_handler_data(irq, its_dev);
>>>> -
>>>> -    addr = its->phys_base + GITS_TRANSLATER;
>>>> -
>>>> -    msg.address_lo        = (u32)addr;
>>>> -    msg.address_hi        = (u32)(addr >> 32);
>>>> -    msg.data        = vec_nr;
>>>> -
>>>> -    write_msi_msg(irq, &msg);
>>>> -    return 0;
>>>> -}
>>>> -
>>>> -static void its_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
>>>> -{
>>>> -    struct irq_data *d = irq_get_irq_data(irq);
>>>> -    struct its_device *its_dev = irq_data_get_irq_handler_data(d);
>>>> -
>>>> -    BUG_ON(d->hwirq < its_dev->lpi_base ||        /* OMG! */
>>>> -           d->hwirq > (its_dev->lpi_base + its_dev->nr_lpis));
>>>> -
>>>> -    /* Stop the delivery of interrupts */
>>>> -    its_send_discard(its_dev, its_msi_get_entry_nr(d->msi_desc));
>>>> -
>>>> -    /* Mark interrupt index as unused, and clear the mapping */
>>>> -    clear_bit(d->hwirq - its_dev->lpi_base, its_dev->lpi_map);
>>>> -    irq_dispose_mapping(irq);
>>>> -
>>>> -    /* If all interrupts have been freed, start mopping the floor */
>>>> -    if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
>>>> -        its_lpi_free(its_dev->lpi_map,
>>>> -                     its_dev->lpi_base,
>>>> -                     its_dev->nr_lpis);
>>>> -
>>>> -        /* Unmap device/itt */
>>>> -        its_send_mapd(its_dev, 0);
>>>> -        its_free_device(its_dev);
>>>> -    }
>>>> -}
>>>> -
>>>
>>>
>>> Those 2 functions seems useful for me. Why did you drop them?
>>
>> These are callbacks registered for msi_chip in linux, Since we have removed
>> msi_chip from its_node structure, these functions are supposed to be removed.
>
> How do you register/unregister MSI in this case?

On receiving MAPD/MAPVI command

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

* Re: [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen
  2015-03-16 16:03         ` Vijay Kilari
@ 2015-03-16 16:18           ` Julien Grall
  0 siblings, 0 replies; 59+ messages in thread
From: Julien Grall @ 2015-03-16 16:18 UTC (permalink / raw)
  To: Vijay Kilari
  Cc: Ian Campbell, Stefano Stabellini, Prasun Kapoor, Vijaya Kumar K,
	Tim Deegan, xen-devel, Stefano Stabellini, manish.jaggi

On 16/03/15 16:03, Vijay Kilari wrote:
>>>> Those 2 functions seems useful for me. Why did you drop them?
>>>
>>> These are callbacks registered for msi_chip in linux, Since we have removed
>>> msi_chip from its_node structure, these functions are supposed to be removed.
>>
>> How do you register/unregister MSI in this case?
> 
> On receiving MAPD/MAPVI command

And no validation at all?

I think your vITS is doing too much things ... the goal of the vITS is
to emulate the hardware and ask the physical IRQ to map a range of LPIs...

-- 
Julien Grall

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

end of thread, other threads:[~2015-03-16 16:18 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-02 12:30 [RFC PATCH 00/19] xen/arm: Add ITS support vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 01/19] xen/arm: add linked list apis vijay.kilari
2015-03-02 13:21   ` Jan Beulich
2015-03-02 12:30 ` [RFC PATCH 02/19] xen/arm: its: Import GICv3 ITS driver from linux vijay.kilari
2015-03-13 10:24   ` Julien Grall
2015-03-13 10:35     ` Julien Grall
2015-03-16  9:55       ` Vijay Kilari
2015-03-16 10:12         ` Stefano Stabellini
2015-03-16 13:04           ` Julien Grall
2015-03-16 13:15         ` Julien Grall
2015-03-16 13:32           ` Vijay Kilari
2015-03-02 12:30 ` [RFC PATCH 03/19] xen/arm: its: Port ITS driver to xen vijay.kilari
2015-03-13 11:46   ` Julien Grall
2015-03-16 14:06     ` Vijay Kilari
2015-03-16 14:20       ` Julien Grall
2015-03-16 16:03         ` Vijay Kilari
2015-03-16 16:18           ` Julien Grall
2015-03-02 12:30 ` [RFC PATCH 04/19] xen/arm: its: Move ITS command encode helper functions vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 05/19] xen/arm: its: Remove unused code in ITS driver vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 06/19] xen/arm: its: Add helper functions to decode ITS Command vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 07/19] xen/arm: vits: Move LPI handling to basic virtual its driver vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 08/19] xen/arm: Add helper function to get domain page vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 09/19] xen/arm: Update irq descriptor for LPIs support vijay.kilari
2015-03-02 14:17   ` Julien Grall
2015-03-03 17:54   ` Stefano Stabellini
2015-03-02 12:30 ` [RFC PATCH 10/19] xen/arm: its: Add virtual ITS command support vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 11/19] xen/arm: its: Add emulation of ITS control registers vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs vijay.kilari
2015-03-03 17:16   ` Stefano Stabellini
2015-03-04 12:10     ` Stefano Stabellini
2015-03-02 12:30 ` [RFC PATCH 13/19] xen/arm: its: implement hw_irq_controller " vijay.kilari
2015-03-03 17:28   ` Stefano Stabellini
2015-03-09 13:03     ` Vijay Kilari
2015-03-09 16:09       ` Stefano Stabellini
2015-03-09 16:32         ` Vijay Kilari
2015-03-02 12:30 ` [RFC PATCH 14/19] xen/arm: vits: Map ITS translation space vijay.kilari
2015-03-03 17:31   ` Stefano Stabellini
2015-03-03 17:41     ` Julien Grall
2015-03-02 12:30 ` [RFC PATCH 15/19] xen/arm: gicv3: Refactor redistributor information vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 16/19] xen/arm: its: Dynamic allocation of LPI descriptors vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 17/19] xen/arm: its: Support ITS interrupt handling vijay.kilari
2015-03-03 18:07   ` Stefano Stabellini
2015-03-03 19:49     ` Julien Grall
2015-03-04  9:57       ` Stefano Stabellini
2015-03-02 12:30 ` [RFC PATCH 18/19] xen/arm: its: Generate ITS node for Dom0 vijay.kilari
2015-03-02 12:30 ` [RFC PATCH 19/19] xen/arm: its: Initialize virtual and physical ITS driver vijay.kilari
2015-03-02 13:19 ` [RFC PATCH 00/19] xen/arm: Add ITS support Julien Grall
2015-03-03  3:55   ` Vijay Kilari
2015-03-03 11:43     ` Julien Grall
2015-03-09 12:57       ` Vijay Kilari
2015-03-09 16:06         ` Stefano Stabellini
2015-03-09 18:16         ` Julien Grall
2015-03-13  4:48           ` Vijay Kilari
2015-03-13 10:13             ` Julien Grall
2015-03-16 10:30               ` Vijay Kilari
2015-03-02 14:53 ` Ian Campbell
2015-03-02 17:39   ` Ian Campbell
2015-03-03  4:02     ` Vijay Kilari
2015-03-03 10:07       ` Ian Campbell

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.