All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 00/28] Add ITS support
@ 2016-02-01  9:26 vijayak
  2016-02-01  9:26 ` [PATCH v8 01/28] xen/arm: Add bitmap_find_next_zero_area helper function vijayak
                   ` (28 more replies)
  0 siblings, 29 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

This is based on DraftG version
http://xenbits.xen.org/people/ianc/vits/draftG.pdf

Following major features are supported
 - GICv3 ITS support for arm64 platform
 - Only Dom0 is supported. For DomU pci passthrough feature
   is required.

Major Changes in v8:
 - Rebased to latest staging branch.
 - Tested with kernel 4.2.
 - Introduced new patch xen/arm: Correct GICD_TYPER register definition typos.
 - Dropped xen/arm: Move vgic rank locking inside get_irq_priority.
   This patch is not required with latest code.
 - Used Tasklet to parse LPI property table.

Changes in v7:

 - Rebased to latest staging branch.
 - Compiled all the patches individually for both arm32 and arm64
 - Patch xen-arm-ITS-implement-hw_irq_controller-for-LPIs.patch
   split into two patches.
      - xen-arm-ITS-implement-hw_irq_controller-for-LPIs.patch and
      - xen-arm-ITS-Plumbing-hw_irq_controller-for-LPIs.patch.
 - Moved patch xen-arm-ITS-Add-GITS-registers-emulation.patch
   before vITS compilation.
 - Merged xen-arm-ITS-Enable-virtual-ITS-driver.patch with
   patch xen-arm-ITS-Export-ITS-info-to-Virtual-ITS.patch.
 - Dropped patch xen-arm-ITS-Add-32-bit-access-to-GICR_TYPER.patch.
   This is only minor change. Hence merged with
   xen-arm-ITS-Add-GICR-register-emulation.patch.
 - Dropped patch xen-arm-ITS-Introduce-helper-to-get-number-of-event-.patch
 - Dropped gic_lpi_supported helper function.
 - Changed LPI property table usage and handling.
 - Added support to pass nr_lpis from bootargs.
 - Added support to enable/disable its support from bootargs.
 - Fixed issues around freeing of its_device on error.
 - Introduced vits.h file
 - Dropped xen-dt-Handle-correctly-node-with-interrupt-map-in-d.patch
   from this series as it is already merged.

  Could not share code via Github. Network is very slow.
  Please, let me know if required.

Changes in v6:

 - Rebased to latest staging branch.
 - Compiled all the patches individually for both arm32 and arm64
 - Split the patch "xen/arm: ITS: Allocate irq descriptors for LPIs" into two.
   One for allocating LPI irq_desc and other patch for allocating pending_irq desc
   for LPIs
 - Following new patches are introduced
     1) xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
     2) xen/arm: ITS: Introduce msi_desc for LPIs
     3) xen/arm: Move vgic locking inside get_irq_priority callback
     4) xen/arm: ITS: Store LPIs allocated and IRQ ID bits per domain
     5) xen/arm: ITS: Introduce helper to get number of event IDs
     6) xen/arm: ITS: Add virtual ITS availability check helper
     7) xen/arm: ITS: Add 32-bit access to GICR_TYPER)
     8) xen/arm: ITS: Allocate pending_lpi descriptors for LPIs

 - Based on below patch set
     http://lists.xen.org/archives/html/xen-devel/2015-08/msg00168.html

 Some Major TODOs:
   1) Avoid making vits_process_cmd() static in later point of time
   2) How to handle LPI that does not have LPI config table entry.
   3) Enable/disable ITS to Dom0

Changes in v5:
  - Added following new patches
      0001-xen-arm-Return-success-if-dt-node-does-not-have-irq-.patch
      0004-xen-arm-Set-nr_cpu_ids-to-available-number-of-cpus.patch
      0009-xen-arm-ITS-Export-ITS-info-to-Virtual-ITS.patch
      0013-xen-arm-ITS-Implement-gic_is_lpi-helper-function.patch
  - Split patch #12 into two patches #14 & #16
      0014-xen-arm-ITS-Allocate-irq-descriptors-for-LPIs.patch
      0016-xen-arm-ITS-Route-LPIs.patch
  - Introduce new API to route LPI (route_lpi_to_guest() )
  - Moved patch #8 in v4 as patch #19
  - irq_descritors for LPIs are allocated dynamically
  - Removed RB-tree for managing vitual its devices. Will be
    introduced when pci-passthrough is implemented
  - its_add_device() api now takes nr_ites and DT its node as parameters
  - some function are kept as non-static when introduced in a patch for
    compilation purpose and eventually made static when used.
  - Tested compilation for arm32

Changes in v4:
  - Patch for rate limiting of error message is removed.
  - Patch #4 and #5 in v3 is merged
  - Merged #13 and #16 as one patch
  - hw_irq_controller is implemented for LPIs
  - GITS and GICR emulation for LPIs in separate patches
  - Removed build functions for ITS command in physical ITS driver
  - Added new patch to add and assign devices from platform file
  - Enable compilation of vits and pits driver in separate patch
  - Replace msi-parent property in all pci dt nodes to single
    ITS node generated by Xen for Dom0

Vijaya Kumar K (28):
  xen/arm: Add bitmap_find_next_zero_area helper function
  xen: Add log2 functionality
  xen/arm: Set nr_cpu_ids to available number of cpus
  xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
  xen/arm: ITS: Port ITS driver to Xen
  xen/arm: ITS: Add helper functions to manage its_devices
  xen/arm: ITS: Introduce msi_desc for LPIs
  xen/arm: ITS: Add APIs to add and assign device
  xen/arm: ITS: Introduce gic_is_lpi helper function
  xen/arm: ITS: Implement hw_irq_controller for LPIs
  xen/arm: ITS: Enable compilation of physical ITS driver
  xen/arm: ITS: Plumb hw_irq_controller for LPIs
  xen/arm: Correct GICD_TYPER register definition typos
  xen/arm: ITS: Initialize physical ITS and export lpi support
  xen/arm: ITS: Add virtual ITS driver
  xen/arm: ITS: Add virtual ITS commands support
  xen/arm: ITS: Add GITS registers emulation
  xen/arm: ITS: Export ITS info to Virtual ITS
  xen/arm: ITS: Store the number of LPIs allocated per domain
  xen/arm: ITS: Add virtual ITS availability check helper
  xen/arm: ITS: Add GICR register emulation
  xen/arm: ITS: Allocate irq descriptors for LPIs
  xen/arm: ITS: Allocate pending_lpi descriptors for LPIs
  xen/arm: ITS: Route LPIs
  xen/arm: ITS: Add domain specific ITS initialization
  xen/arm: ITS: Map ITS translation space
  xen/arm: ITS: Generate ITS node for Dom0
  xen/arm: ITS: Add pci devices in ThunderX

 docs/misc/xen-command-line.markdown |    7 +
 xen/arch/arm/Makefile               |    2 +
 xen/arch/arm/domain_build.c         |   14 +
 xen/arch/arm/gic-hip04.c            |   20 +-
 xen/arch/arm/gic-v2.c               |   22 +-
 xen/arch/arm/gic-v3-its.c           | 1658 +++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c               |  155 +++-
 xen/arch/arm/gic.c                  |   56 +-
 xen/arch/arm/irq.c                  |  171 +++-
 xen/arch/arm/platforms/Makefile     |    1 +
 xen/arch/arm/platforms/thunderx.c   |  200 +++++
 xen/arch/arm/setup.c                |    2 +
 xen/arch/arm/vgic-v2.c              |    2 +-
 xen/arch/arm/vgic-v3-its.c          |  988 +++++++++++++++++++++
 xen/arch/arm/vgic-v3.c              |  437 ++++++++-
 xen/arch/arm/vgic.c                 |  196 ++++-
 xen/common/bitmap.c                 |   39 +
 xen/include/asm-arm/domain.h        |   35 +
 xen/include/asm-arm/gic-its.h       |  320 +++++++
 xen/include/asm-arm/gic.h           |   31 +-
 xen/include/asm-arm/gic_v3_defs.h   |   68 +-
 xen/include/asm-arm/irq.h           |   21 +-
 xen/include/asm-arm/vgic.h          |   23 +-
 xen/include/asm-arm/vits.h          |  107 +++
 xen/include/xen/bitmap.h            |   16 +
 xen/include/xen/lib.h               |    2 +
 xen/include/xen/log2.h              |  167 ++++
 27 files changed, 4661 insertions(+), 99 deletions(-)
 create mode 100644 xen/arch/arm/gic-v3-its.c
 create mode 100644 xen/arch/arm/platforms/thunderx.c
 create mode 100644 xen/arch/arm/vgic-v3-its.c
 create mode 100644 xen/include/asm-arm/gic-its.h
 create mode 100644 xen/include/asm-arm/vits.h
 create mode 100644 xen/include/xen/log2.h

-- 
1.7.9.5

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

* [PATCH v8 01/28] xen/arm: Add bitmap_find_next_zero_area helper function
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 02/28] xen: Add log2 functionality vijayak
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Keir Fraser, Ian Campbell, vijay.kilari, Prasun.Kapoor,
	manish.jaggi, Ian Jackson, Jan Beulich, Vijaya Kumar K

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

bitmap_find_next_zero_area helper function will be used
by physical ITS driver. This is imported from linux 4.2

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Jan Beulich <jbeulich@suse.com>
CC: Keir Fraser <keir@xen.org>
CC: Tim Deegan <tim@xen.org>
---
v5: Ported from Linux 4.2.
    Added bitmap_find_next_zero_area_off().
v4: Removed spaces and added tabs
    Moved ALIGN macro to lib.h
v3: Moved changes to xen/common/bitmap.c and
    xen/include/xen/bitmap.h
---
 xen/common/bitmap.c      |   39 +++++++++++++++++++++++++++++++++++++++
 xen/include/xen/bitmap.h |   16 ++++++++++++++++
 xen/include/xen/lib.h    |    2 ++
 3 files changed, 57 insertions(+)

diff --git a/xen/common/bitmap.c b/xen/common/bitmap.c
index 61d1ea4..ad665d1 100644
--- a/xen/common/bitmap.c
+++ b/xen/common/bitmap.c
@@ -489,6 +489,45 @@ int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
 }
 EXPORT_SYMBOL(bitmap_allocate_region);
 
+/*
+ * bitmap_find_next_zero_area_off - find a contiguous aligned zero area
+ * @map: The address to base the search on
+ * @size: The bitmap size in bits
+ * @start: The bitnumber to start searching at
+ * @nr: The number of zeroed bits we're looking for
+ * @align_mask: Alignment mask for zero area
+ * @align_offset: Alignment offset for zero area.
+ *
+ * The @align_mask should be one less than a power of 2; the effect is that
+ * the bit offset of all zero areas this function finds plus @align_offset
+ * is multiple of that power of 2.
+ */
+unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
+					     unsigned long size,
+					     unsigned long start,
+					     unsigned int nr,
+					     unsigned long align_mask,
+					     unsigned long align_offset)
+{
+	unsigned long index, end, i;
+again:
+	index = find_next_zero_bit(map, size, start);
+
+	/* Align allocation */
+	index = ALIGN_MASK(index + align_offset, align_mask) - align_offset;
+
+	end = index + nr;
+	if (end > size)
+		return end;
+	i = find_next_bit(map, end, index);
+	if (i < end) {
+		start = i + 1;
+		goto again;
+	}
+	return index;
+}
+EXPORT_SYMBOL(bitmap_find_next_zero_area_off)
+
 #ifdef __BIG_ENDIAN
 
 void bitmap_long_to_byte(uint8_t *bp, const unsigned long *lp, int nbits)
diff --git a/xen/include/xen/bitmap.h b/xen/include/xen/bitmap.h
index e2a3686..161f990 100644
--- a/xen/include/xen/bitmap.h
+++ b/xen/include/xen/bitmap.h
@@ -101,6 +101,22 @@ extern int bitmap_scnlistprintf(char *buf, unsigned int len,
 extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order);
 extern void bitmap_release_region(unsigned long *bitmap, int pos, int order);
 extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order);
+extern unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
+						    unsigned long size,
+						    unsigned long start,
+						    unsigned int nr,
+						    unsigned long align_mask,
+						    unsigned long align_offset);
+
+static inline unsigned long bitmap_find_next_zero_area(unsigned long *map,
+						       unsigned long size,
+						       unsigned long start,
+						       unsigned int nr,
+						       unsigned long align_mask)
+{
+	return bitmap_find_next_zero_area_off(map, size, start, nr,
+					      align_mask, 0);
+}
 
 #define BITMAP_LAST_WORD_MASK(nbits)					\
 (									\
diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h
index 4258912..e7d9d95 100644
--- a/xen/include/xen/lib.h
+++ b/xen/include/xen/lib.h
@@ -55,6 +55,8 @@
 
 #define ROUNDUP(x, a) (((x) + (a) - 1) & ~((a) - 1))
 
+#define ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
+
 #define reserve_bootmem(_p,_l) ((void)0)
 
 struct domain;
-- 
1.7.9.5

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

* [PATCH v8 02/28] xen: Add log2 functionality
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
  2016-02-01  9:26 ` [PATCH v8 01/28] xen/arm: Add bitmap_find_next_zero_area helper function vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 03/28] xen/arm: Set nr_cpu_ids to available number of cpus vijayak
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Keir Fraser, Ian Campbell, vijay.kilari, Prasun.Kapoor,
	manish.jaggi, Ian Jackson, Jan Beulich, Vijaya Kumar K

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

log2 helper apis are ported from linux from
commit 13c07b0286d340275f2d97adf085cecda37ede37
(linux/log2.h: Fix rounddown_pow_of_two(1))
Changes made for xen are:
  - Only required functionality is retained
  - Replace fls_long with flsl

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Jan Beulich <jbeulich@suse.com>
CC: Keir Fraser <keir@xen.org>
CC: Tim Deegan <tim@xen.org>
---
v4: - Only retained required functionality
    - Replaced fls_long with flsl
    - Removed fls_long implementation in bitops.h in v3 version
---
 xen/include/xen/log2.h |  167 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 167 insertions(+)

diff --git a/xen/include/xen/log2.h b/xen/include/xen/log2.h
new file mode 100644
index 0000000..86bd861
--- /dev/null
+++ b/xen/include/xen/log2.h
@@ -0,0 +1,167 @@
+/* 
+ * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _XEN_LOG2_H
+#define _XEN_LOG2_H
+
+#include <xen/types.h>
+#include <xen/bitops.h>
+
+/*
+ * deal with unrepresentable constant logarithms
+ */
+extern __attribute__((const))
+int ____ilog2_NaN(void);
+
+/*
+ * non-constant log of base 2 calculators
+ * - the arch may override these in asm/bitops.h if they can be implemented
+ *   more efficiently than using fls() and fls64()
+ * - the arch is not required to handle n==0 if implementing the fallback
+ */
+static inline __attribute__((const))
+int __ilog2_u32(u32 n)
+{
+	return fls(n) - 1;
+}
+
+static inline __attribute__((const))
+int __ilog2_u64(u64 n)
+{
+	return flsl(n) - 1;
+}
+
+/*
+ * round up to nearest power of two
+ */
+static inline __attribute__((const))
+unsigned long __roundup_pow_of_two(unsigned long n)
+{
+	return 1UL << flsl(n - 1);
+}
+
+/**
+ * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value
+ * @n - parameter
+ *
+ * constant-capable log of base 2 calculation
+ * - this can be used to initialise global variables from constant data, hence
+ *   the massive ternary operator construction
+ *
+ * selects the appropriately-sized optimised version depending on sizeof(n)
+ */
+#define ilog2(n)				\
+(						\
+	__builtin_constant_p(n) ? (		\
+		(n) < 1 ? ____ilog2_NaN() :	\
+		(n) & (1ULL << 63) ? 63 :	\
+		(n) & (1ULL << 62) ? 62 :	\
+		(n) & (1ULL << 61) ? 61 :	\
+		(n) & (1ULL << 60) ? 60 :	\
+		(n) & (1ULL << 59) ? 59 :	\
+		(n) & (1ULL << 58) ? 58 :	\
+		(n) & (1ULL << 57) ? 57 :	\
+		(n) & (1ULL << 56) ? 56 :	\
+		(n) & (1ULL << 55) ? 55 :	\
+		(n) & (1ULL << 54) ? 54 :	\
+		(n) & (1ULL << 53) ? 53 :	\
+		(n) & (1ULL << 52) ? 52 :	\
+		(n) & (1ULL << 51) ? 51 :	\
+		(n) & (1ULL << 50) ? 50 :	\
+		(n) & (1ULL << 49) ? 49 :	\
+		(n) & (1ULL << 48) ? 48 :	\
+		(n) & (1ULL << 47) ? 47 :	\
+		(n) & (1ULL << 46) ? 46 :	\
+		(n) & (1ULL << 45) ? 45 :	\
+		(n) & (1ULL << 44) ? 44 :	\
+		(n) & (1ULL << 43) ? 43 :	\
+		(n) & (1ULL << 42) ? 42 :	\
+		(n) & (1ULL << 41) ? 41 :	\
+		(n) & (1ULL << 40) ? 40 :	\
+		(n) & (1ULL << 39) ? 39 :	\
+		(n) & (1ULL << 38) ? 38 :	\
+		(n) & (1ULL << 37) ? 37 :	\
+		(n) & (1ULL << 36) ? 36 :	\
+		(n) & (1ULL << 35) ? 35 :	\
+		(n) & (1ULL << 34) ? 34 :	\
+		(n) & (1ULL << 33) ? 33 :	\
+		(n) & (1ULL << 32) ? 32 :	\
+		(n) & (1ULL << 31) ? 31 :	\
+		(n) & (1ULL << 30) ? 30 :	\
+		(n) & (1ULL << 29) ? 29 :	\
+		(n) & (1ULL << 28) ? 28 :	\
+		(n) & (1ULL << 27) ? 27 :	\
+		(n) & (1ULL << 26) ? 26 :	\
+		(n) & (1ULL << 25) ? 25 :	\
+		(n) & (1ULL << 24) ? 24 :	\
+		(n) & (1ULL << 23) ? 23 :	\
+		(n) & (1ULL << 22) ? 22 :	\
+		(n) & (1ULL << 21) ? 21 :	\
+		(n) & (1ULL << 20) ? 20 :	\
+		(n) & (1ULL << 19) ? 19 :	\
+		(n) & (1ULL << 18) ? 18 :	\
+		(n) & (1ULL << 17) ? 17 :	\
+		(n) & (1ULL << 16) ? 16 :	\
+		(n) & (1ULL << 15) ? 15 :	\
+		(n) & (1ULL << 14) ? 14 :	\
+		(n) & (1ULL << 13) ? 13 :	\
+		(n) & (1ULL << 12) ? 12 :	\
+		(n) & (1ULL << 11) ? 11 :	\
+		(n) & (1ULL << 10) ? 10 :	\
+		(n) & (1ULL <<  9) ?  9 :	\
+		(n) & (1ULL <<  8) ?  8 :	\
+		(n) & (1ULL <<  7) ?  7 :	\
+		(n) & (1ULL <<  6) ?  6 :	\
+		(n) & (1ULL <<  5) ?  5 :	\
+		(n) & (1ULL <<  4) ?  4 :	\
+		(n) & (1ULL <<  3) ?  3 :	\
+		(n) & (1ULL <<  2) ?  2 :	\
+		(n) & (1ULL <<  1) ?  1 :	\
+		(n) & (1ULL <<  0) ?  0 :	\
+		____ilog2_NaN()			\
+				   ) :		\
+	(sizeof(n) <= 4) ?			\
+	__ilog2_u32(n) :			\
+	__ilog2_u64(n)				\
+ )
+
+/**
+ * roundup_pow_of_two - round the given value up to nearest power of two
+ * @n - parameter
+ *
+ * round the given value up to the nearest power of two
+ * - the result is undefined when n == 0
+ * - this can be used to initialise global variables from constant data
+ */
+#define roundup_pow_of_two(n)			\
+(						\
+	__builtin_constant_p(n) ? (		\
+		(n == 1) ? 1 :			\
+		(1UL << (ilog2((n) - 1) + 1))	\
+				   ) :		\
+	__roundup_pow_of_two(n)			\
+ )
+
+/**
+ * order_base_2 - calculate the (rounded up) base 2 order of the argument
+ * @n: parameter
+ *
+ * The first few values calculated by this routine:
+ *  ob2(0) = 0
+ *  ob2(1) = 0
+ *  ob2(2) = 1
+ *  ob2(3) = 2
+ *  ob2(4) = 2
+ *  ob2(5) = 3
+ *  ... and so on.
+ */
+
+#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+#endif /* _XEN_LOG2_H */
-- 
1.7.9.5

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

* [PATCH v8 03/28] xen/arm: Set nr_cpu_ids to available number of cpus
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
  2016-02-01  9:26 ` [PATCH v8 01/28] xen/arm: Add bitmap_find_next_zero_area helper function vijayak
  2016-02-01  9:26 ` [PATCH v8 02/28] xen: Add log2 functionality vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 04/28] xen/arm: Rename NR_IRQs and vgic_num_irqs helper function vijayak
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

nr_cpu_ids for arm platforms is incorrectly set to NR_CPUS
irrespective of the number of cpus supported by platform.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Reviewed-by: Julien Grall <julien.grall@citrix.com>
---
v6: - Updated nr_cpu_ids in setup.c instead of creating
      a helper function
---
 xen/arch/arm/setup.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index e95759d..fac74d4 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -771,6 +771,8 @@ void __init start_xen(unsigned long boot_phys_offset,
 
     smp_init_cpus();
     cpus = smp_get_max_cpus();
+    printk(XENLOG_INFO "SMP: Allowing %u CPUs\n", cpus);
+    nr_cpu_ids = cpus;
 
     init_xen_time();
 
-- 
1.7.9.5

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

* [PATCH v8 04/28] xen/arm: Rename NR_IRQs and vgic_num_irqs helper function
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (2 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 03/28] xen/arm: Set nr_cpu_ids to available number of cpus vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 05/28] xen/arm: ITS: Port ITS driver to Xen vijayak
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

NR_IRQS represents the number of lines (i.e SGIs, PPIs and SPIs).
With the introduction of LPIs, NR_IRQs is renamed to NR_ITLINES.
Similarly vgic_num_irqs() is renamed as vgic_num_irq_lines().

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Reviewed-by: Julien Grall <julien.grall@citrix.com>
---
v7: - Renamed NR_LINE_IRQS as NR_ITLINES and vgic_num_line_irqs()
      as vgic_num_irq_lines()
---
 xen/arch/arm/gic.c         |    2 +-
 xen/arch/arm/irq.c         |   10 +++++-----
 xen/arch/arm/vgic-v3.c     |    2 +-
 xen/arch/arm/vgic.c        |   10 +++++-----
 xen/include/asm-arm/irq.h  |    9 +++++----
 xen/include/asm-arm/vgic.h |    2 +-
 6 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 0b3f634..4b46a71 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -140,7 +140,7 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
     ASSERT(spin_is_locked(&desc->lock));
     /* Caller has already checked that the IRQ is an SPI */
     ASSERT(virq >= 32);
-    ASSERT(virq < vgic_num_irqs(d));
+    ASSERT(virq < vgic_num_irq_lines(d));
 
     vgic_lock_rank(v_target, rank, flags);
 
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index d409abb..b722737 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -55,7 +55,7 @@ hw_irq_controller no_irq_type = {
     .end = end_none
 };
 
-static irq_desc_t irq_desc[NR_IRQS];
+static irq_desc_t irq_desc[NR_ITLINES];
 static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
 
 irq_desc_t *__irq_to_desc(int irq)
@@ -75,7 +75,7 @@ static int __init init_irq_data(void)
 {
     int irq;
 
-    for (irq = NR_LOCAL_IRQS; irq < NR_IRQS; irq++) {
+    for (irq = NR_LOCAL_IRQS; irq < NR_ITLINES; irq++) {
         struct irq_desc *desc = irq_to_desc(irq);
         init_one_irq_desc(desc);
         desc->irq = irq;
@@ -407,11 +407,11 @@ int route_irq_to_guest(struct domain *d, unsigned int virq,
     unsigned long flags;
     int retval = 0;
 
-    if ( virq >= vgic_num_irqs(d) )
+    if ( virq >= vgic_num_irq_lines(d) )
     {
         printk(XENLOG_G_ERR
                "the vIRQ number %u is too high for domain %u (max = %u)\n",
-               irq, d->domain_id, vgic_num_irqs(d));
+               irq, d->domain_id, vgic_num_irq_lines(d));
         return -EINVAL;
     }
 
@@ -523,7 +523,7 @@ int release_guest_irq(struct domain *d, unsigned int virq)
     int ret;
 
     /* Only SPIs are supported */
-    if ( virq < NR_LOCAL_IRQS || virq >= vgic_num_irqs(d) )
+    if ( virq < NR_LOCAL_IRQS || virq >= vgic_num_irq_lines(d) )
         return -EINVAL;
 
     p = spi_to_pending(d, virq);
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index dba2449..70cf67e 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -909,7 +909,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
          * Number of interrupt identifier bits supported by the GIC
          * Stream Protocol Interface
          */
-        unsigned int irq_bits = get_count_order(vgic_num_irqs(v->domain));
+        unsigned int irq_bits = get_count_order(vgic_num_irq_lines(v->domain));
         /*
          * Number of processors that may be used as interrupt targets when ARE
          * bit is zero. The maximum is 8.
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index ee35683..8cb3b06 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -143,7 +143,7 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis)
         return ret;
 
     d->arch.vgic.allocated_irqs =
-        xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d)));
+        xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irq_lines(d)));
     if ( !d->arch.vgic.allocated_irqs )
         return -ENOMEM;
 
@@ -299,7 +299,7 @@ void arch_move_irqs(struct vcpu *v)
     struct vcpu *v_target;
     int i;
 
-    for ( i = 32; i < vgic_num_irqs(d); i++ )
+    for ( i = 32; i < vgic_num_irq_lines(d); i++ )
     {
         v_target = vgic_get_target_vcpu(v, i);
         p = irq_to_pending(v_target, i);
@@ -505,7 +505,7 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq)
     struct vcpu *v;
 
     /* the IRQ needs to be an SPI */
-    ASSERT(virq >= 32 && virq <= vgic_num_irqs(d));
+    ASSERT(virq >= 32 && virq <= vgic_num_irq_lines(d));
 
     v = vgic_get_target_vcpu(d->vcpu[0], virq);
     vgic_vcpu_inject_irq(v, virq);
@@ -527,7 +527,7 @@ int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
 
 bool_t vgic_reserve_virq(struct domain *d, unsigned int virq)
 {
-    if ( virq >= vgic_num_irqs(d) )
+    if ( virq >= vgic_num_irq_lines(d) )
         return 0;
 
     return !test_and_set_bit(virq, d->arch.vgic.allocated_irqs);
@@ -547,7 +547,7 @@ int vgic_allocate_virq(struct domain *d, bool_t spi)
     else
     {
         first = 32;
-        end = vgic_num_irqs(d);
+        end = vgic_num_irq_lines(d);
     }
 
     /*
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index f33c331..9be83b4 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -19,11 +19,12 @@ struct arch_irq_desc {
 };
 
 #define NR_LOCAL_IRQS	32
-#define NR_IRQS		1024
+/* Number of SGIs + PPIs + SPIs */
+#define NR_ITLINES	1024
 
-#define nr_irqs NR_IRQS
-#define nr_static_irqs NR_IRQS
-#define arch_hwdom_irqs(domid) NR_IRQS
+#define nr_irqs NR_ITLINES
+#define nr_static_irqs NR_ITLINES
+#define arch_hwdom_irqs(domid) NR_ITLINES
 
 struct irq_desc;
 struct irqaction;
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index a2fccc0..e9ec764 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -285,7 +285,7 @@ enum gic_sgi_mode;
  */
 #define REG_RANK_INDEX(b, n, s) ((((n) >> s) & ((b)-1)) % 32)
 
-#define vgic_num_irqs(d)        ((d)->arch.vgic.nr_spis + 32)
+#define vgic_num_irq_lines(d)   ((d)->arch.vgic.nr_spis + 32)
 
 extern int domain_vgic_init(struct domain *d, unsigned int nr_spis);
 extern void domain_vgic_free(struct domain *d);
-- 
1.7.9.5

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

* [PATCH v8 05/28] xen/arm: ITS: Port ITS driver to Xen
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (3 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 04/28] xen/arm: Rename NR_IRQs and vgic_num_irqs helper function vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 06/28] xen/arm: ITS: Add helper functions to manage its_devices vijayak
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

The linux driver is based on 4.1 with below commit id

591e5bec13f15feb13fc445b6c9c59954711c4ac

Only following code from Linux ITS driver is ported
and compiled
 - LPI initialization
 - ITS configuration code
 - Physical command queue management
 - ITS command building

Also redistributor information is split into rdist and
rdist_prop structures.

The rdist_prop struct holds the redistributor common
information for all re-distributor and rdist struct
holds the per-cpu specific information.

This per-cpu rdist is defined as global and shared with
physical ITS driver.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Sorted and used u64 for all fields in command structure
v7:
  - Introduced back its_send_inv()
  - Fix coding styles
v6:
  - made dump_cmd() static and const parameter
  - Include commit 591e5bec13f15feb13fc445b6c9c59954711c4ac
    "irqchip/gicv3-its: Fix mapping of LPIs to collections".
  - reodered its_alloc_lpi_tables() and its_lpi_init()
v5:
  - dump_cmd is called from its_flush_cmd
  - Added its_lpi_alloc_chunks, lpi_free, its_send_inv, its_send_mapd,
    its_send_mapvi to this patch as these functions are ported from
    linux and more logical to be in this patch.
    For now these functions are non-static. Will be made static
    when used.
  - Used this_cpu instead of per_cpu
  - Moved GITS_* definitions to git-its.h
v4: Major changes
  - Redistributor refactoring patch is merged
  - Fixed comments from v3 related to coding style and
    removing duplicate code.
  - Target address is stored from bits[48:16] to avoid
    shifting of target address while building ITS commands
  - Removed non-static functions
  - Removed usage of command builder functions
  - Changed its_cmd_block union to include mix of bit and unsigned
    variable types to define ITS command structure
v3:
  - Only required changes from Linux ITS driver is ported
  - Xen coding style is followed.
---
 xen/arch/arm/gic-v3-its.c         | 1026 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c             |   15 +-
 xen/include/asm-arm/gic-its.h     |  288 +++++++++++
 xen/include/asm-arm/gic.h         |    1 +
 xen/include/asm-arm/gic_v3_defs.h |   46 ++
 5 files changed, 1371 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
new file mode 100644
index 0000000..dac3326
--- /dev/null
+++ b/xen/arch/arm/gic-v3-its.c
@@ -0,0 +1,1026 @@
+/*
+ * 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/>.
+ */
+
+#include <xen/config.h>
+#include <xen/bitops.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/errno.h>
+#include <xen/delay.h>
+#include <xen/list.h>
+#include <xen/sizes.h>
+#include <xen/vmap.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>
+#include <asm/gic-its.h>
+#include <xen/log2.h>
+
+#define its_print(lvl, fmt, ...)                                      \
+    printk(lvl "GIC-ITS:" fmt, ## __VA_ARGS__)
+
+#define its_err(fmt, ...) its_print(XENLOG_ERR, fmt, ## __VA_ARGS__)
+/* TODO: ratelimit for Xen messages */
+#define its_err_ratelimited(fmt, ...)                                 \
+    its_print(XENLOG_G_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 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_FLAGS_CMDQ_NEEDS_FLUSHING         (1 << 0)
+#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING   (1 << 0)
+
+/*
+ * The ITS structure - contains most of the infrastructure, with the
+ * msi_controller, the command queue, the collections, and the list of
+ * devices writing to it.
+ */
+struct its_node {
+    spinlock_t              lock;
+    struct list_head        entry;
+    void __iomem            *base;
+    paddr_t                 phys_base;
+    paddr_t                 phys_size;
+    its_cmd_block           *cmd_base;
+    its_cmd_block           *cmd_write;
+    void                    *tables[GITS_BASER_NR_REGS];
+    u32                     order[GITS_BASER_NR_REGS];
+    struct its_collection   *collections;
+    u64                     flags;
+    u32                     ite_size;
+    struct dt_device_node   *dt_node;
+};
+
+#define ITS_ITT_ALIGN    SZ_256
+
+static LIST_HEAD(its_nodes);
+static DEFINE_SPINLOCK(its_lock);
+static struct rdist_prop  *gic_rdists;
+
+#define gic_data_rdist()    (this_cpu(rdist))
+
+#ifdef DEBUG_GIC_ITS
+static void dump_cmd(const its_cmd_block *cmd)
+{
+    printk(XENLOG_DEBUG
+           "ITS: CMD[0] = 0x%lx CMD[1] = 0x%lx CMD[2] = 0x%lx CMD[3] = 0x%lx\n",
+           cmd->bits[0], cmd->bits[1], cmd->bits[2], cmd->bits[3]);
+}
+#else
+static void dump_cmd(const its_cmd_block *cmd) { }
+#endif
+
+static struct its_collection *dev_event_to_col(struct its_device *dev,
+                                               u32 event)
+{
+    struct its_node *its = dev->its;
+
+    return its->collections + dev->event_map.col_map[event];
+}
+
+#define ITS_CMD_QUEUE_SZ            SZ_64K
+#define ITS_CMD_QUEUE_NR_ENTRIES    (ITS_CMD_QUEUE_SZ / sizeof(its_cmd_block))
+
+static u64 its_cmd_ptr_to_offset(struct its_node *its, 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(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 its_cmd_block *its_allocate_entry(struct its_node *its)
+{
+    its_cmd_block *cmd;
+    u32 count = 1000000;    /* 1s! */
+
+    while ( its_queue_full(its) )
+    {
+        count--;
+        if ( !count )
+        {
+            its_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 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, its_cmd_block *cmd)
+{
+    /*
+     * Make sure the commands written to memory are observable by
+     * the ITS.
+     */
+    if ( its->flags & ITS_FLAGS_CMDQ_NEEDS_FLUSHING )
+        clean_and_invalidate_dcache_va_range(cmd, sizeof(*cmd));
+    else
+        dsb(ishst);
+
+    dump_cmd(cmd);
+}
+
+static void its_wait_for_range_completion(struct its_node *its,
+                                          its_cmd_block *from,
+                                          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 )
+        {
+            its_err_ratelimited("ITS queue timeout\n");
+            return;
+        }
+        cpu_relax();
+        udelay(1);
+    }
+}
+
+static void its_send_single_command(struct its_node *its,
+                                    its_cmd_block *src,
+                                    struct its_collection *sync_col)
+{
+    its_cmd_block *cmd, *sync_cmd, *next_cmd;
+    unsigned long flags;
+
+    BUILD_BUG_ON(sizeof(its_cmd_block) != 32);
+
+    spin_lock_irqsave(&its->lock, flags);
+
+    cmd = its_allocate_entry(its);
+    if ( !cmd )
+    {   /* We're soooooo screewed... */
+        its_err_ratelimited("ITS can't allocate, dropping command\n");
+        spin_unlock_irqrestore(&its->lock, flags);
+        return;
+    }
+
+    memcpy(cmd, src, sizeof(its_cmd_block));
+    its_flush_cmd(its, cmd);
+
+    if ( sync_col )
+    {
+        sync_cmd = its_allocate_entry(its);
+        if ( !sync_cmd )
+        {
+            its_err_ratelimited("ITS can't SYNC, skipping\n");
+            goto post;
+        }
+        sync_cmd->sync.cmd = GITS_CMD_SYNC;
+        sync_cmd->sync.target_addr = sync_col->target_address;
+
+        its_flush_cmd(its, sync_cmd);
+    }
+
+post:
+    next_cmd = its_post_commands(its);
+    spin_unlock_irqrestore(&its->lock, flags);
+
+    its_wait_for_range_completion(its, cmd, next_cmd);
+}
+
+static void its_send_inv(struct its_device *dev, u32 event)
+{
+    its_cmd_block cmd;
+    struct its_collection *col = dev_event_to_col(dev, event);
+
+    memset(&cmd, 0x0, sizeof(its_cmd_block));
+    cmd.inv.cmd = GITS_CMD_INV;
+    cmd.inv.devid = dev->device_id;
+    cmd.inv.event = event;
+
+    its_send_single_command(dev->its, &cmd, col);
+}
+
+static void its_send_mapd(struct its_device *dev, int valid)
+{
+    its_cmd_block cmd;
+    unsigned long itt_addr;
+    u8 size;
+
+    size = ilog2(dev->event_map.nr_lpis);
+    itt_addr = __pa(dev->itt);
+    itt_addr = ROUNDUP(itt_addr, ITS_ITT_ALIGN);
+
+    memset(&cmd, 0x0, sizeof(its_cmd_block));
+    cmd.mapd.cmd = GITS_CMD_MAPD;
+    cmd.mapd.devid = dev->device_id;
+    cmd.mapd.size = size - 1;
+    /*
+     * ITT address field of MAPD command holds bit[48:8] of
+     * itt address. Hence shift by 8.
+     */
+    cmd.mapd.itt = itt_addr >> 8;
+    cmd.mapd.valid =  !!valid;
+
+    its_send_single_command(dev->its, &cmd, NULL);
+}
+
+static void its_send_mapc(struct its_node *its, struct its_collection *col,
+                          int valid)
+{
+    its_cmd_block cmd;
+
+    memset(&cmd, 0x0, sizeof(its_cmd_block));
+    cmd.mapc.cmd = GITS_CMD_MAPC;
+    cmd.mapc.col = col->col_id;
+    cmd.mapc.ta = col->target_address;
+    cmd.mapc.valid = !!valid;
+
+    its_send_single_command(its, &cmd, col);
+}
+
+static void its_send_mapvi(struct its_device *dev, u32 phys_id, u32 event)
+{
+    its_cmd_block cmd;
+    struct its_collection *col = dev_event_to_col(dev, event);
+
+    memset(&cmd, 0x0, sizeof(its_cmd_block));
+    cmd.mapvi.cmd = GITS_CMD_MAPVI;
+    cmd.mapvi.devid = dev->device_id;
+    cmd.mapvi.event = event;
+    cmd.mapvi.phy_id = phys_id;
+    cmd.mapvi.col = col->col_id;
+
+    its_send_single_command(dev->its, &cmd, col);
+}
+
+static void its_send_invall(struct its_node *its, struct its_collection *col)
+{
+    its_cmd_block cmd;
+
+    memset(&cmd, 0x0, sizeof(its_cmd_block));
+    cmd.invall.cmd = GITS_CMD_INVALL;
+    cmd.invall.col = col->col_id;
+
+    its_send_single_command(its, &cmd, NULL);
+}
+
+static void its_send_discard(struct its_device *dev, u32 event)
+{
+    its_cmd_block cmd;
+    struct its_collection *col = dev_event_to_col(dev, event);
+
+    memset(&cmd, 0x0, sizeof(its_cmd_block));
+    cmd.discard.devid = dev->device_id;
+    cmd.discard.event = event;
+
+    its_send_single_command(dev->its, &cmd, 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;
+}
+
+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 = xzalloc_bytes(BITS_TO_LONGS(lpi_chunks) * sizeof(long));
+    if ( !lpi_bitmap )
+    {
+        lpi_chunks = 0;
+        return -ENOMEM;
+    }
+
+    its_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
+
+    return 0;
+}
+
+static unsigned long *its_lpi_alloc_chunks(int nirqs, int *base)
+{
+    unsigned long *bitmap = NULL;
+    int chunk_id, nr_chunks, nr_ids, i;
+
+    nr_chunks = DIV_ROUND_UP(nirqs, 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 = 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;
+
+    if ( nr_ids < nirqs )
+    {
+        xfree(bitmap);
+        bitmap = NULL;
+    }
+
+out:
+    spin_unlock(&lpi_lock);
+
+    return bitmap;
+}
+
+static void its_lpi_free(struct its_device *dev)
+{
+    int lpi;
+
+    spin_lock(&lpi_lock);
+
+    for ( lpi = dev->event_map.lpi_base;
+          lpi < (dev->event_map.lpi_base + dev->event_map.nr_lpis);
+          lpi += IRQS_PER_CHUNK )
+    {
+        int chunk = its_lpi_to_chunk(lpi);
+
+        if (chunk > lpi_chunks)
+            its_err("Bad LPI chunk %d\n", chunk);
+        if ( test_bit(chunk, lpi_bitmap) )
+            clear_bit(chunk, lpi_bitmap);
+    }
+
+    spin_unlock(&lpi_lock);
+
+    xfree(dev->event_map.lpi_map);
+    xfree(dev->event_map.col_map);
+}
+
+/*
+ * 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)
+
+static int __init its_alloc_lpi_tables(void)
+{
+    paddr_t paddr;
+
+    gic_rdists->prop_page =
+           alloc_xenheap_pages(get_order_from_bytes(LPI_PROPBASE_SZ), 0);
+
+    if ( !gic_rdists->prop_page )
+    {
+        its_err("Failed to allocate PROPBASE\n");
+        return -ENOMEM;
+    }
+
+    paddr = __pa(gic_rdists->prop_page);
+    its_info("GIC: using LPI property table @%pa\n", &paddr);
+
+    /* Set LPI priority and Group-1, but disabled */
+    memset(gic_rdists->prop_page,
+           GIC_PRI_IRQ | LPI_PROP_GROUP1,
+           LPI_PROPBASE_SZ);
+
+    /* Make sure the GIC will observe the written configuration */
+    clean_and_invalidate_dcache_va_range(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_xenheap_pages(its->tables[i], its->order[i]);
+            its->tables[i] = NULL;
+            its->order[i] = 0;
+        }
+    }
+}
+
+static int its_alloc_tables(struct its_node *its)
+{
+    int err;
+    int i;
+    int psz = SZ_64K;
+    u64 shr = GITS_BASER_InnerShareable;
+    u64 cache = GITS_BASER_WaWb;
+
+    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);
+        unsigned int order = get_order_from_bytes(psz);
+        int alloc_size;
+        u64 tmp;
+        void *base;
+
+        if ( type == GITS_BASER_TYPE_NONE )
+            continue;
+
+        /*
+         * Allocate as many entries as required to fit the
+         * range of device IDs that the ITS can grok... The ID
+         * space being incredibly sparse, this results in a
+         * massive waste of memory.
+         *
+         * For other tables, only allocate a single page.
+         */
+        if ( type == GITS_BASER_TYPE_DEVICE )
+        {
+            u64 typer = readq_relaxed(its->base + GITS_TYPER);
+            u32 ids = GITS_TYPER_DEVBITS(typer);
+
+            order = max(get_order_from_bytes((1UL << ids) * entry_size), order);
+            if (order >= MAX_ORDER)
+            {
+                order = MAX_ORDER - 1;
+                its_warn("Device Table too large,reduce its page order to %u\n",
+                         order);
+            }
+        }
+
+        alloc_size = (1 << order) * PAGE_SIZE;
+        base = alloc_xenheap_pages(order, 0);
+        if ( !base )
+        {
+            err = -ENOMEM;
+            goto out_free;
+        }
+        memset(base, 0, alloc_size);
+        its->tables[i] = base;
+        its->order[i] = order;
+
+retry_baser:
+        val = (__pa(base)                                        |
+               (type << GITS_BASER_TYPE_SHIFT)                   |
+               ((entry_size - 1) << GITS_BASER_ENTRY_SIZE_SHIFT) |
+               cache                                             |
+               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 |= (alloc_size / psz) - 1;
+
+        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;
+            if ( !shr )
+                cache = GITS_BASER_nC;
+            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;
+            }
+        }
+
+        if ( val != 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;
+        }
+
+        its_info("ITS: allocated %d %s @%lx (psz %dK, shr %d)\n",
+                 (int)(alloc_size / entry_size),
+                 its_base_type_string[type],
+                 (unsigned long)__pa(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 = xzalloc_array(struct its_collection, nr_cpu_ids);
+    if ( !its->collections )
+        return -ENOMEM;
+
+    return 0;
+}
+
+static void its_cpu_init_lpis(void)
+{
+    void __iomem *rbase = gic_data_rdist().rbase;
+    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;
+    if ( !pend_page )
+    {
+        paddr_t paddr;
+        u32 order;
+
+        /*
+         * The pending pages have to be at least 64kB aligned,
+         * hence the 'max(LPI_PENDBASE_SZ, SZ_64K)' below.
+         */
+        order = get_order_from_bytes(max(LPI_PENDBASE_SZ, SZ_64K));
+        pend_page = alloc_xenheap_pages(order, 0);
+        if ( !pend_page )
+        {
+            its_err("Failed to allocate PENDBASE for CPU%d with order %d\n",
+                    smp_processor_id(), order);
+            return;
+        }
+
+        memset(pend_page, 0, max(LPI_PENDBASE_SZ, SZ_64K));
+        /* Make sure the GIC will observe the zero-ed page */
+        clean_and_invalidate_dcache_va_range(pend_page, LPI_PENDBASE_SZ);
+
+        paddr = __pa(pend_page);
+
+        its_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 = (__pa(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 )
+    {
+        if ( !(tmp & GICR_PROPBASER_SHAREABILITY_MASK) )
+        {
+            /*
+             * The HW reports non-shareable, we must
+             * remove the cacheability attributes as well.
+             */
+            val &= ~(GICR_PROPBASER_SHAREABILITY_MASK |
+                     GICR_PROPBASER_CACHEABILITY_MASK);
+            val |= GICR_PROPBASER_nC;
+            writeq_relaxed(val, rbase + GICR_PROPBASER);
+        }
+
+        its_info("GIC: using cache flushing for LPI property table\n");
+        gic_rdists->flags |= RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING;
+    }
+
+    /* set PENDBASE */
+    val = (__pa(pend_page)               |
+           GICR_PROPBASER_InnerShareable |
+           GICR_PROPBASER_WaWb);
+
+    writeq_relaxed(val, rbase + GICR_PENDBASER);
+    tmp = readq_relaxed(rbase + GICR_PENDBASER);
+
+    if ( !(tmp & GICR_PENDBASER_SHAREABILITY_MASK) )
+    {
+        /*
+         * The HW reports non-shareable, we must remove the
+         * cacheability attributes as well.
+         */
+        val &= ~(GICR_PENDBASER_SHAREABILITY_MASK |
+                 GICR_PENDBASER_CACHEABILITY_MASK);
+        val |= GICR_PENDBASER_nC;
+        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 )
+        {
+            target = gic_data_rdist().phys_base;
+            /* ITS command considers only [48:16] of the GICR address */
+            target >>= 16;
+        }
+        else
+        {
+            /*
+             * This ITS wants a linear CPU number.
+             */
+            target = readq_relaxed(gic_data_rdist().rbase + GICR_TYPER);
+            target = GICR_TYPER_CPU_NUMBER(target);
+        }
+
+        /* Perform collection mapping */
+        its->collections[cpu].col_id = cpu;
+        its->collections[cpu].target_address = target;
+
+        its_send_mapc(its, &its->collections[cpu], 1);
+        its_send_invall(its, &its->collections[cpu]);
+    }
+
+    spin_unlock(&its_lock);
+}
+
+static int its_force_quiescent(void __iomem *base)
+{
+    u32 count = 1000000;   /* 1s */
+    u32 val;
+
+    val = readl_relaxed(base + GITS_CTLR);
+    if ( val & GITS_CTLR_QUIESCENT )
+        return 0;
+
+    /* Disable the generation of all interrupts to this ITS */
+    val &= ~GITS_CTLR_ENABLE;
+    writel_relaxed(val, base + GITS_CTLR);
+
+    /* Poll GITS_CTLR and wait until ITS becomes quiescent */
+    while ( 1 )
+    {
+        val = readl_relaxed(base + GITS_CTLR);
+        if ( val & GITS_CTLR_QUIESCENT )
+            return 0;
+
+        count--;
+        if ( !count )
+            return -EBUSY;
+
+        cpu_relax();
+        udelay(1);
+    }
+}
+
+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, typer;
+    u64 baser, tmp;
+    int err;
+
+    if ( !dt_get_property(node, "msi-controller", NULL) )
+    {
+        its_warn("%s: not a msi-controller\n", node->full_name);
+        return -ENXIO;
+    }
+
+    err = dt_device_get_address(node, 0, &its_addr, &its_size);
+    if ( err )
+    {
+        its_warn("%s: no regs?\n", node->full_name);
+        return -ENXIO;
+    }
+
+    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_REV_MASK;
+    if ( val != 0x30 && val != 0x40 )
+    {
+        its_warn("%s: no ITS detected, giving up\n", node->full_name);
+        err = -ENODEV;
+        goto out_unmap;
+    }
+
+    err = its_force_quiescent(its_base);
+    if ( err )
+    {
+        its_warn("%s: failed to quiesce, giving up\n",
+                 node->full_name);
+        goto out_unmap;
+    }
+
+    its_info("ITS: %s\n", node->full_name);
+
+    its = xzalloc(struct its_node);
+    if ( !its )
+    {
+        err = -ENOMEM;
+        goto out_unmap;
+    }
+
+    spin_lock_init(&its->lock);
+    INIT_LIST_HEAD(&its->entry);
+    its->dt_node = node;
+    its->base = its_base;
+    its->phys_base = its_addr;
+    its->phys_size = its_size;
+    typer = readl_relaxed(its_base + GITS_TYPER);
+    its->ite_size = ((typer >> 4) & 0xf) + 1;
+
+    its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
+    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 = (__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);
+    if ( (tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK )
+    {
+        if (!(tmp & GITS_CBASER_SHAREABILITY_MASK))
+        {
+            /*
+             * The HW reports non-shareable, we must
+             * remove the cacheability attributes as
+             * well.
+             */
+            baser &= ~(GITS_CBASER_SHAREABILITY_MASK |
+                       GITS_CBASER_CACHEABILITY_MASK);
+            baser |= GITS_CBASER_nC;
+            writeq_relaxed(baser, its->base + GITS_CBASER);
+        }
+
+        its_info("ITS: using cache flushing for cmd queue\n");
+        its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
+    }
+
+    writeq_relaxed(0, its->base + GITS_CWRITER);
+    writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
+
+    spin_lock(&its_lock);
+    list_add(&its->entry, &its_nodes);
+    spin_unlock(&its_lock);
+
+    return 0;
+
+out_free_tables:
+    its_free_tables(its);
+out_free_cmd:
+    xfree(its->cmd_base);
+out_free_its:
+    xfree(its);
+out_unmap:
+    iounmap(its_base);
+    its_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().rbase + GICR_TYPER) &
+              GICR_TYPER_PLPIS);
+}
+
+int its_cpu_init(void)
+{
+    if ( !list_empty(&its_nodes) )
+    {
+        if ( !gic_rdists_supports_plpis() )
+        {
+            its_info("CPU%d: LPIs not supported\n", smp_processor_id());
+            return -ENXIO;
+        }
+        its_cpu_init_lpis();
+        its_cpu_init_collection();
+    }
+
+    return 0;
+}
+
+int __init its_init(struct rdist_prop *rdists)
+{
+    struct dt_device_node *np = NULL;
+
+    static const struct dt_device_match its_device_ids[] __initconst =
+    {
+        DT_MATCH_GIC_ITS,
+        { /* sentinel */ },
+    };
+
+    for ( np = dt_find_matching_node(NULL, its_device_ids); np;
+          np = dt_find_matching_node(np, its_device_ids) )
+        its_probe(np);
+
+    if ( list_empty(&its_nodes) )
+    {
+        its_warn("ITS: No ITS available, not enabling LPIs\n");
+        return -ENXIO;
+    }
+
+    gic_rdists = rdists;
+    its_alloc_lpi_tables();
+    its_lpi_init(rdists->id_bits);
+
+    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 a245b56..a8082ab 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -45,6 +45,7 @@
 /* Global state */
 static struct {
     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 */
@@ -55,10 +56,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        (this_cpu(rdist).rbase)
 #define GICD_RDIST_SGI_BASE    (GICD_RDIST_BASE + SZ_64K)
 
 /*
@@ -618,6 +619,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());
 
     /*
@@ -653,9 +655,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;
+                this_cpu(rdist).rbase = ptr;
+                this_cpu(rdist).phys_base =  gicv3.rdist_regions[i].base + offset;
+                printk("GICv3: CPU%d: Found redistributor in region %d @%"PRIpaddr"\n",
+                        smp_processor_id(), i,
+                        this_cpu(rdist).phys_base);
                 return 0;
             }
             if ( gicv3.rdist_stride )
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
new file mode 100644
index 0000000..7f12d5b
--- /dev/null
+++ b/xen/include/asm-arm/gic-its.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2015 Cavium Inc.
+ * Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.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/>.
+ */
+
+#ifndef __ASM_ARM_GIC_ITS_H__
+#define __ASM_ARM_GIC_ITS_H__
+
+#include <asm/gic_v3_defs.h>
+
+/*
+ * 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_BASER0                     0x0100
+#define GITS_BASER1                     0x0108
+#define GITS_BASER                      0x0100
+#define GITS_BASERN                     0x0138
+#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_CTLR_QUIESCENT             (1U << 31)
+#define GITS_CTLR_ENABLE                (1U << 0)
+
+#define GITS_TYPER_DEVBITS_SHIFT        13
+#define GITS_TYPER_DEVBITS(r)           ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
+#define GITS_TYPER_IDBITS_SHIFT         8
+#define GITS_TYPER_IDBITS(r)		((((r) >> GITS_TYPER_IDBITS_SHIFT) & 0x1f) + 1)
+#define GITS_TYPER_PTA                  (1UL << 19)
+#define GITS_TYPER_HCC_SHIFT            (24)
+
+#define GITS_CBASER_VALID               (1UL << 63)
+#define GITS_CBASER_nC                  (1UL << 59)
+#define GITS_CBASER_WaWb                (5UL << 59)
+#define GITS_CBASER_InnerShareable      (1UL << 10)
+#define GITS_CBASER_SHAREABILITY_MASK   (3UL << 10)
+#define GITS_CBASER_CACHEABILITY_MASK   (7UL << 59)
+
+#define GITS_BASER_NR_REGS              8
+
+#define GITS_BASER_VALID                (1UL << 63)
+#define GITS_BASER_nC                   (1UL << 59)
+#define GITS_BASER_WaWb                 (5UL << 59)
+#define GITS_BASER_TYPE_SHIFT           (56)
+#define GITS_BASER_TYPE_MASK            (0x7)
+#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_InnerShareable       (1UL << 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
+
+#define LPI_PROP_ENABLED                (1 << 0)
+#define LPI_PROP_GROUP1                 (1 << 1)
+
+/*
+ * Collection structure - just an ID, and a redistributor address to
+ * ping. We use one per CPU as collection of interrupts assigned to this
+ * CPU.
+ */
+struct its_collection {
+    u64 target_address;
+    u16 col_id;
+};
+
+/* ITS command structure */
+typedef union {
+    u64 bits[4];
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:56;
+        u64 res2[3];
+    } hdr;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 event:32;
+        u64 res2:32;
+        u64 res3;
+        u64 res4;
+    } clear;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 event:32;
+        u64 res2:32;
+        u64 res3;
+        u64 res4;
+    } discard;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 event:32;
+        u64 res2:32;
+        u64 res3;
+        u64 res4;
+    } int_cmd;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 event:32;
+        u64 res2:32;
+        u64 res3;
+        u64 res4;
+    } inv;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:56;
+        u64 res2;
+        u64 col:16;
+        u64 res3:48;
+        u64 res4;
+    } invall;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:56;
+        u64 res2;
+        u64 col:16;
+        u64 ta:32;
+        u64 res3:15;
+        u64 valid:1;
+        u64 res4;
+    } mapc;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 size:5;
+        u64 res2:59;
+        /*
+         * ITT address is 48 bit address. Mapd command takes
+         * only top 40 bits (bits [48:8]) of address in itt field.
+         * So code using mapd_cmd struct has to shift ITT address by 8.
+         * TODO: This shift can be avoided if itt field size is set to 48.
+         */
+        u64 res3:8;
+        u64 itt:40;
+        u64 res4:15;
+        u64 valid:1;
+        u64 res5;
+    } mapd;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 event:32;
+        u64 res2:32;
+        u64 col:16;
+        u64 res3:48;
+        u64 res4;
+    } mapi;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 event:32;
+        u64 phy_id:32;
+        u64 col:16;
+        u64 res2:48;
+        u64 res3;
+    } mapvi;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:56;
+        u64 res2;
+        u64 res3:16;
+        u64 target_addr1:32;
+        u64 res4:16;
+        u64 res5:16;
+        u64 target_addr2:32;
+        u64 res6:16;
+    } movall;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:24;
+        u64 devid:32;
+        u64 event:32;
+        u64 res2:32;
+        u64 col:16;
+        u64 res3:48;
+        u64 res4;
+    } movi;
+    struct __packed {
+        u64 cmd:8;
+        u64 res1:56;
+        u64 res2;
+        u64 res3:16;
+        u64 target_addr:32;
+        u64 res4:16;
+        u64 res5;
+    } sync;
+} its_cmd_block;
+
+struct event_lpi_map {
+    /* Physical LPI map */
+    unsigned long *lpi_map;
+    /* Collection map */
+    u16           *col_map;
+    /* First Physical LPI number assigned */
+    u32           lpi_base;
+    /* Number of ITES/Physical LPIs assigned */
+    u32           nr_lpis;
+};
+
+/*
+ * The ITS view of a device.
+ */
+struct its_device {
+    /* Physical ITS */
+    struct its_node         *its;
+    /* Device ITT address */
+    void                    *itt;
+    /* Device ITT size */
+    unsigned long           itt_size;
+    /* LPI and event mapping */
+    struct event_lpi_map    event_map;
+    /* Physical Device id */
+    u32                     device_id;
+};
+
+int its_init(struct rdist_prop *rdists);
+int its_cpu_init(void);
+
+#endif /* __ASM_ARM_GIC_ITS_H__ */
+/*
+ * 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.h b/xen/include/asm-arm/gic.h
index 7bd06e1..6189ac9 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -166,6 +166,7 @@
     DT_MATCH_COMPATIBLE("arm,gic-400")
 
 #define DT_MATCH_GIC_V3 DT_MATCH_COMPATIBLE("arm,gic-v3")
+#define DT_MATCH_GIC_ITS DT_MATCH_COMPATIBLE("arm,gic-v3-its")
 
 #ifdef CONFIG_HAS_GICV3
 /*
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 6d98491..d675a4d 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -46,6 +46,7 @@
 /* Additional bits in GICD_TYPER defined by GICv3 */
 #define GICD_TYPE_ID_BITS_SHIFT 19
 
+#define GICD_TYPER_LPIS_SUPPORTED    (1U << 17)
 #define GICD_CTLR_RWP                (1UL << 31)
 #define GICD_CTLR_ARE_NS             (1U << 4)
 #define GICD_CTLR_ENABLE_G1A         (1U << 1)
@@ -57,6 +58,15 @@
 #define GICR_WAKER_ProcessorSleep    (1U << 1)
 #define GICR_WAKER_ChildrenAsleep    (1U << 2)
 
+#define GIC_PIDR2_ARCH_REV_MASK      (0xf0)
+#define GICD_PIDR2_ARCH_REV_MASK     GIC_PIDR2_ARCH_REV_MASK
+#define GICD_PIDR2_ARCH_REV_SHIFT    (0x4)
+#define GICD_PIDR2_ARCH_GICV3        (0x3)
+
+#define GICR_PIDR2_ARCH_REV_MASK     GIC_PIDR2_ARCH_REV_MASK
+#define GICR_PIDR2_ARCH_REV_SHIFT    GICD_PIDR2_ARCH_REV_SHIFT
+#define GICR_PIDR2_ARCH_GICV3        GICD_PIDR2_ARCH_GICV3
+
 #define GICR_SYNCR_NOT_BUSY          1
 /*
  * Implementation defined value JEP106?
@@ -95,10 +105,24 @@
 #define GICR_IGRPMODR0               (0x0D00)
 #define GICR_NSACR                   (0x0E00)
 
+#define GICR_CTLR_ENABLE_LPIS        (1UL << 0)
+#define GICR_TYPER_CPU_NUMBER(r)     (((r) >> 8) & 0xffff)
+
+#define GICR_PROPBASER_InnerShareable    (1U << 10)
+#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PROPBASER_nC                (1U << 7)
+#define GICR_PROPBASER_WaWb              (5U << 7)
+#define GICR_PROPBASER_CACHEABILITY_MASK (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)
 
+#define GICR_PENDBASER_InnerShareable    (1U << 10)
+#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
+#define GICR_PENDBASER_nC                (1U << 7)
+#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+
 #define DEFAULT_PMR_VALUE            0xff
 
 #define GICH_VMCR_EOI                (1 << 9)
@@ -143,6 +167,28 @@ struct rdist_region {
     void __iomem *map_base;
 };
 
+/* Re-distributor per-cpu information */
+struct rdist {
+    /* CPU Re-distributor address */
+    void __iomem *rbase;
+    /* CPU LPI pending table */
+    void *pend_page;
+    /* CPU Re-distributor physical address */
+    paddr_t phys_base;
+};
+
+/* Common Re-distributor information */
+struct rdist_prop {
+    /* CPUs LPI configuration table */
+    void *prop_page;
+    /* Number of ID bits */
+    int id_bits;
+    /* Flags to store rdist attributes */
+    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] 31+ messages in thread

* [PATCH v8 06/28] xen/arm: ITS: Add helper functions to manage its_devices
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (4 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 05/28] xen/arm: ITS: Port ITS driver to Xen vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 07/28] xen/arm: ITS: Introduce msi_desc for LPIs vijayak
                   ` (22 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Helper functions to manage its devices using RB-tree
are introduced in physical ITS driver.

This is global list of all the devices.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Added assert on lock in its_remove_device()
    - Dropped Ack's from Ian and Julien
v7: - Introduce its_remove_device api to remove device
      from rb-tree
v5: - Added assert on spinlock
v4: - Remove passing of root node as parameter
    - Declare prototype in header file
    - Rename find_its_device to its_find_device
---
 xen/arch/arm/gic-v3-its.c     |   61 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic-its.h |    3 ++
 2 files changed, 64 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index dac3326..2716137 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -93,6 +93,8 @@ struct its_node {
 static LIST_HEAD(its_nodes);
 static DEFINE_SPINLOCK(its_lock);
 static struct rdist_prop  *gic_rdists;
+static struct rb_root rb_its_dev;
+static DEFINE_SPINLOCK(rb_its_dev_lock);
 
 #define gic_data_rdist()    (this_cpu(rdist))
 
@@ -115,6 +117,63 @@ static struct its_collection *dev_event_to_col(struct its_device *dev,
     return its->collections + dev->event_map.col_map[event];
 }
 
+/* RB-tree helpers for its_device */
+static struct its_device *its_find_device(u32 devid)
+{
+    struct rb_node *node = rb_its_dev.rb_node;
+
+    ASSERT(spin_is_locked(&rb_its_dev_lock));
+    while ( node )
+    {
+        struct its_device *dev;
+
+        dev = container_of(node, struct its_device, node);
+        if ( devid < dev->device_id )
+            node = node->rb_left;
+        else if ( devid > dev->device_id )
+            node = node->rb_right;
+        else
+            return dev;
+    }
+
+    return NULL;
+}
+
+static int its_insert_device(struct its_device *dev)
+{
+    struct rb_node **new, *parent;
+
+    ASSERT(spin_is_locked(&rb_its_dev_lock));
+    new = &rb_its_dev.rb_node;
+    parent = NULL;
+    while ( *new )
+    {
+        struct its_device *this;
+
+        this  = container_of(*new, struct its_device, node);
+        parent = *new;
+        if ( dev->device_id < this->device_id )
+            new = &((*new)->rb_left);
+        else if ( dev->device_id > this->device_id )
+            new = &((*new)->rb_right);
+        else
+            return -EEXIST;
+    }
+
+    rb_link_node(&dev->node, parent, new);
+    rb_insert_color(&dev->node, &rb_its_dev);
+
+    return 0;
+}
+
+static void its_remove_device(struct its_device *dev)
+{
+    ASSERT(spin_is_locked(&rb_its_dev_lock));
+
+    if ( dev )
+        rb_erase(&dev->node, &rb_its_dev);
+}
+
 #define ITS_CMD_QUEUE_SZ            SZ_64K
 #define ITS_CMD_QUEUE_NR_ENTRIES    (ITS_CMD_QUEUE_SZ / sizeof(its_cmd_block))
 
@@ -953,6 +1012,8 @@ static int its_probe(struct dt_device_node *node)
     list_add(&its->entry, &its_nodes);
     spin_unlock(&its_lock);
 
+    rb_its_dev = RB_ROOT;
+
     return 0;
 
 out_free_tables:
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 7f12d5b..c950097 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -19,6 +19,7 @@
 #define __ASM_ARM_GIC_ITS_H__
 
 #include <asm/gic_v3_defs.h>
+#include <xen/rbtree.h>
 
 /*
  * ITS registers, offsets from ITS_base
@@ -272,6 +273,8 @@ struct its_device {
     struct event_lpi_map    event_map;
     /* Physical Device id */
     u32                     device_id;
+    /* RB-tree entry */
+    struct rb_node          node;
 };
 
 int its_init(struct rdist_prop *rdists);
-- 
1.7.9.5

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

* [PATCH v8 07/28] xen/arm: ITS: Introduce msi_desc for LPIs
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (5 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 06/28] xen/arm: ITS: Add helper functions to manage its_devices vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 08/28] xen/arm: ITS: Add APIs to add and assign device vijayak
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Define msi_desc structure for arm and introduce
helper functions to access msi_desc member variables.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Reviewed-by: Julien Grall <julien.grall@citrix.com>
---
 xen/arch/arm/gic-v3-its.c     |   28 ++++++++++++++++++++++++++++
 xen/arch/arm/irq.c            |   12 ++++++++++++
 xen/include/asm-arm/gic-its.h |    4 ++++
 xen/include/asm-arm/irq.h     |    9 +++++++++
 4 files changed, 53 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 2716137..205b610 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -109,6 +109,34 @@ static void dump_cmd(const its_cmd_block *cmd)
 static void dump_cmd(const its_cmd_block *cmd) { }
 #endif
 
+void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id)
+{
+    ASSERT(spin_is_locked(&desc->lock));
+
+    irq_get_msi_desc(desc)->eventID = id;
+}
+
+unsigned int irqdesc_get_lpi_event(struct irq_desc *desc)
+{
+    ASSERT(spin_is_locked(&desc->lock));
+
+    return irq_get_msi_desc(desc)->eventID;
+}
+
+struct its_device *irqdesc_get_its_device(struct irq_desc *desc)
+{
+    ASSERT(spin_is_locked(&desc->lock));
+
+    return irq_get_msi_desc(desc)->dev;
+}
+
+void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev)
+{
+    ASSERT(spin_is_locked(&desc->lock));
+
+    irq_get_msi_desc(desc)->dev = dev;
+}
+
 static struct its_collection *dev_event_to_col(struct its_device *dev,
                                                u32 event)
 {
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index b722737..3baac5d 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -143,6 +143,18 @@ static inline struct domain *irq_get_domain(struct irq_desc *desc)
     return irq_get_guest_info(desc)->d;
 }
 
+void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi)
+{
+    desc->msi_desc = msi;
+}
+
+struct msi_desc *irq_get_msi_desc(struct irq_desc *desc)
+{
+    ASSERT(desc->msi_desc != NULL);
+
+    return desc->msi_desc;
+}
+
 void irq_set_affinity(struct irq_desc *desc, const cpumask_t *cpu_mask)
 {
     if ( desc != NULL )
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index c950097..70065be 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -277,6 +277,10 @@ struct its_device {
     struct rb_node          node;
 };
 
+void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
+unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
+struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
+void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
 int its_init(struct rdist_prop *rdists);
 int its_cpu_init(void);
 
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 9be83b4..4bb9464 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -18,6 +18,13 @@ struct arch_irq_desc {
     unsigned int type;
 };
 
+struct msi_desc {
+#ifdef CONFIG_HAS_GICV3
+    unsigned int eventID;
+    struct its_device *dev;
+#endif
+};
+
 #define NR_LOCAL_IRQS	32
 /* Number of SGIs + PPIs + SPIs */
 #define NR_ITLINES	1024
@@ -56,6 +63,8 @@ int irq_set_spi_type(unsigned int spi, unsigned int type);
 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);
+void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi);
+struct msi_desc *irq_get_msi_desc(struct irq_desc *desc);
 
 #endif /* _ASM_HW_IRQ_H */
 /*
-- 
1.7.9.5

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

* [PATCH v8 08/28] xen/arm: ITS: Add APIs to add and assign device
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (6 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 07/28] xen/arm: ITS: Introduce msi_desc for LPIs vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 09/28] xen/arm: ITS: Introduce gic_is_lpi helper function vijayak
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Add APIs to add devices to RB-tree, assign and remove
devices to domain.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Merged its_free_msi_descs() with its_discard_lpis
    - Dropped extra spin_unlock() in its_assign_device()
    - Dropped check on device domain to be dom0 in assign_device()
    - device is assigned to domain in assign_device() instead
      of add_device() function
    - Replaced XENLOG_E_ERR with XENLOG_ERR

v7: - Added check for domain in its_assign_device() to avoid
      assigning device to DomU
    - Added comments whereever requested
    - Called its_remove_device to remove from rb-tree
      when failed to add device
    - Changed dprintk to printk
    - Store domain pointer instead of domain id in its_device struct
    - Free msi_desc and reset irq_desc when lpis are discarded
    - Add function its_free_msi_descs() to free msi_desc
v6: - Moved this patch #19 to patch #8
    - Used col_map to store collection id
    - Use helper functions to update msi_desc members
v5: - Removed its_detach_device API
    - Pass nr_ites as parameter to its_add_device
v4: - Introduced helper to populate its_device struct
    - Fixed freeing of its_device memory
    - its_device struct holds domain id
---
 xen/arch/arm/gic-v3-its.c     |  252 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic-its.h |    6 +
 2 files changed, 258 insertions(+)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 205b610..c233950 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -145,6 +145,19 @@ static struct its_collection *dev_event_to_col(struct its_device *dev,
     return its->collections + dev->event_map.col_map[event];
 }
 
+static struct its_node *its_get_phys_node(struct dt_device_node *dt)
+{
+    struct its_node *its;
+
+    list_for_each_entry(its, &its_nodes, entry)
+    {
+        if ( its->dt_node == dt )
+            return its;
+    }
+
+    return NULL;
+}
+
 /* RB-tree helpers for its_device */
 static struct its_device *its_find_device(u32 devid)
 {
@@ -544,6 +557,245 @@ static void its_lpi_free(struct its_device *dev)
     xfree(dev->event_map.col_map);
 }
 
+static inline u32 its_get_plpi(struct its_device *dev, u32 event)
+{
+    return dev->event_map.lpi_base + event;
+}
+
+static void its_discard_lpis(struct its_device *dev, u32 ids)
+{
+    u32 i;
+    struct irq_desc *desc;
+
+    for ( i = 0; i < ids; i++ )
+    {
+       its_send_discard(dev, i);
+       desc = irq_to_desc(its_get_plpi(dev, i));
+
+       spin_lock(&desc->lock);
+       irqdesc_set_lpi_event(desc, 0);
+       irqdesc_set_its_device(desc, NULL);
+       /*
+        * Here only msi_descs are cleaned.
+        * TODO: Clean irq_descs of this pLPIs.
+        */
+       xfree(irq_get_msi_desc(desc));
+       irq_set_msi_desc(desc, NULL);
+       spin_unlock(&desc->lock);
+    }
+}
+
+static int its_alloc_device_irq(struct its_device *dev, u32 *hwirq)
+{
+    int idx;
+
+    idx = find_first_zero_bit(dev->event_map.lpi_map, dev->event_map.nr_lpis);
+    if ( idx == dev->event_map.nr_lpis )
+        return -ENOSPC;
+
+    *hwirq = its_get_plpi(dev, idx);
+    set_bit(idx, dev->event_map.lpi_map);
+
+    return 0;
+}
+
+static void its_free_device(struct its_device *dev)
+{
+    xfree(dev->itt);
+    its_lpi_free(dev);
+    xfree(dev);
+}
+
+static struct its_device *its_alloc_device(u32 devid, u32 nr_ites,
+                                           struct dt_device_node *dt_its)
+{
+    struct its_device *dev;
+    unsigned long *lpi_map;
+    int lpi_base, sz;
+    u16 *col_map = NULL;
+
+    dev = xzalloc(struct its_device);
+    if ( dev == NULL )
+        return NULL;
+
+    dev->its = its_get_phys_node(dt_its);
+    if ( dev->its == NULL )
+    {
+        printk(XENLOG_ERR
+               "ITS: Failed to find ITS node for devid 0x%"PRIx32"\n", devid);
+        goto err;
+    }
+
+    /*
+     * At least one bit of EventID is being used, hence a minimum
+     * of two entries. No, the architecture doesn't let you
+     * express an ITT with a single entry.
+     */
+    nr_ites = max(2UL, roundup_pow_of_two(nr_ites));
+    sz = nr_ites * dev->its->ite_size;
+    sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
+
+    dev->itt = xzalloc_bytes(sz);
+    if ( !dev->itt )
+        goto err;
+
+    lpi_map = its_lpi_alloc_chunks(nr_ites, &lpi_base);
+    if ( !lpi_map )
+        goto lpi_err;
+
+    col_map = xzalloc_bytes(sizeof(*col_map) * nr_ites);
+    if ( !col_map )
+        goto col_err;
+
+    dev->event_map.lpi_map = lpi_map;
+    dev->event_map.lpi_base = lpi_base;
+    dev->event_map.col_map = col_map;
+    dev->event_map.nr_lpis = nr_ites;
+    dev->device_id = devid;
+
+    return dev;
+
+col_err:
+    its_free_device(dev);
+    return NULL;
+lpi_err:
+    xfree(dev->itt);
+err:
+    xfree(dev);
+
+    return NULL;
+}
+
+/* Device assignment */
+int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its)
+{
+    struct its_device *dev;
+    u32 i, plpi = 0;
+    struct its_collection *col;
+    struct irq_desc *desc;
+    struct msi_desc *msi = NULL;
+    int res = 0;
+
+    spin_lock(&rb_its_dev_lock);
+    dev = its_find_device(devid);
+    if ( dev )
+    {
+        printk(XENLOG_ERR "ITS: Device already exists 0x%"PRIx32"\n",
+               dev->device_id);
+        res = -EEXIST;
+        goto err_unlock;
+    }
+
+    dev = its_alloc_device(devid, nr_ites, dt_its);
+    if ( !dev )
+    {
+        res = -ENOMEM;
+        goto err_unlock;
+    }
+
+    BUG_ON(its_insert_device(dev));
+    spin_unlock(&rb_its_dev_lock);
+
+    DPRINTK("ITS:Add Device 0x%"PRIx32" lpis %"PRIu32" base 0x%"PRIx32"\n",
+            dev->device_id, dev->event_map.nr_lpis, dev->event_map.lpi_base);
+
+    /* Map device to ITS ITT */
+    its_send_mapd(dev, 1);
+
+    for ( i = 0; i < dev->event_map.nr_lpis; i++ )
+    {
+        msi = xzalloc(struct msi_desc);
+        if ( its_alloc_device_irq(dev, &plpi) || !msi )
+        {
+            /* Discard LPIs and free device on failure to allocate pLPI */
+            its_discard_lpis(dev, i);
+            its_send_mapd(dev, 0);
+
+            spin_lock(&rb_its_dev_lock);
+            its_remove_device(dev);
+            spin_unlock(&rb_its_dev_lock);
+
+            its_free_device(dev);
+
+            printk(XENLOG_ERR "ITS: Cannot add device 0x%"PRIx32"\n", devid);
+            res = -ENOSPC;
+            goto err;
+        }
+
+        /*
+         * Each Collection is mapped to one physical CPU and
+         * each pLPI allocated to this device is mapped one collection
+         * in a round robin fashion. Hence all pLPIs are distributed
+         * across all processors in the system.
+         * With this approach, multiple devices having same eventID
+         * will be mapped to same cpu.
+         */
+        col = &dev->its->collections[(i % nr_cpu_ids)];
+        desc = irq_to_desc(plpi);
+
+        spin_lock(&desc->lock);
+        dev->event_map.col_map[i] = col->col_id;
+        irq_set_msi_desc(desc, msi);
+        irqdesc_set_lpi_event(desc, i);
+        irqdesc_set_its_device(desc, dev);
+        spin_unlock(&desc->lock);
+
+        /* For each pLPI send MAPVI command */
+        its_send_mapvi(dev, plpi, i);
+    }
+
+    return 0;
+
+err_unlock:
+    spin_unlock(&rb_its_dev_lock);
+err:
+    return res;
+}
+
+int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid)
+{
+    struct its_device *pdev;
+    u32 plpi, i;
+
+    DPRINTK("ITS: Assign request for dev 0x%"PRIx32" to domain %"PRIu16"\n",
+            vdevid, d->domain_id);
+
+    spin_lock(&rb_its_dev_lock);
+    pdev = its_find_device(pdevid);
+    spin_unlock(&rb_its_dev_lock);
+    if ( !pdev )
+        return -ENODEV;
+
+    /*
+     * TODO: For pass-through following has to be implemented
+     * 1) Allow device to be assigned to other domains (Dom0 -> DomU).
+     * 2) Allow device to be re-assigned to Dom0 (DomU -> Dom0).
+     * Implement separate function to handle this or rework this function.
+     * For now do not allow assigning devices other than Dom0.
+     */
+    if ( !is_hardware_domain(d) )
+    {
+        printk(XENLOG_ERR
+               "ITS: PCI-Passthrough not supported!! to assign from d%d to d%d",
+               pdev->domain->domain_id, d->domain_id);
+        return -ENXIO;
+    }
+
+    pdev->domain = d;
+    pdev->virt_device_id = vdevid;
+
+    DPRINTK("ITS: Assign pdevid 0x%"PRIx32" lpis %"PRIu32" for dom %"PRIu16"\n",
+            pdevid, pdev->event_map.nr_lpis, d->domain_id);
+
+    for ( i = 0; i < pdev->event_map.nr_lpis; i++ )
+    {
+        plpi = its_get_plpi(pdev, i);
+        /* TODO: Route lpi */
+    }
+
+    return 0;
+}
+
 /*
  * We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to
  * deal with (one configuration byte per interrupt). PENDBASE has to
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 70065be..7fd7140 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -273,6 +273,10 @@ struct its_device {
     struct event_lpi_map    event_map;
     /* Physical Device id */
     u32                     device_id;
+    /* Virtual Device id */
+    u32                     virt_device_id;
+    /* Domain assigned */
+    struct domain           *domain;
     /* RB-tree entry */
     struct rb_node          node;
 };
@@ -283,6 +287,8 @@ struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
 void irqdesc_set_its_device(struct irq_desc *desc, struct its_device *dev);
 int its_init(struct rdist_prop *rdists);
 int its_cpu_init(void);
+int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
+int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
 
 #endif /* __ASM_ARM_GIC_ITS_H__ */
 /*
-- 
1.7.9.5

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

* [PATCH v8 09/28] xen/arm: ITS: Introduce gic_is_lpi helper function
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (7 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 08/28] xen/arm: ITS: Add APIs to add and assign device vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 10/28] xen/arm: ITS: Implement hw_irq_controller for LPIs vijayak
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Zoltan Kiss, Vijaya Kumar K, vijay.kilari

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

Helper function gic_is_lpi() is used to find
if irq is lpi or not. For GICv2 platforms this function
returns number of irq ids which represents only number of line irqs.
For GICv3 platform irq ids are calculated from nr_lpis if
HW supports LPIs

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
CC: Zoltan Kiss <zoltan.kiss@huawei.com>
---
v8: - Move nr_lpis command line option to gic-v3.c.
    - nr_lpis is initialized only if ITS is supported.
    - Updates doc for nr_lpis command line option.
    - Used msi command line option to enable/disable ITS.
v7: - Rename gic_info.nr_id_bits as gic_info.nr_irq_ids
    - gic_is_lpi() is common for both ARM64/32
    - Introduce global variable nr_lpis from patch #17
    - Reset nr_lpis to 0 when HW does not support LPIs
    - pass nr_lpis as boot args to Xen. Set minimum to 8192
v6: - Added gic_info.nr_id_bits to hold number of SPI/LPIs
      supported
    - Dropped is_lpi() callback
---
 docs/misc/xen-command-line.markdown |    7 +++++
 xen/arch/arm/gic-hip04.c            |    2 ++
 xen/arch/arm/gic-v2.c               |    2 ++
 xen/arch/arm/gic-v3.c               |   49 +++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic.c                  |   10 +++++++
 xen/include/asm-arm/gic.h           |    5 ++++
 6 files changed, 75 insertions(+)

diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index d267a04..dcbc838 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1556,3 +1556,10 @@ mode.
 > Default: `true`
 
 Permit use of the `xsave/xrstor` instructions.
+
+### nr_lpis (ARM)
+> `= <integer>`
+
+> Default: `8192`
+
+Number of LPIs supported by Xen.
diff --git a/xen/arch/arm/gic-hip04.c b/xen/arch/arm/gic-hip04.c
index a42cf24..9a4091b 100644
--- a/xen/arch/arm/gic-hip04.c
+++ b/xen/arch/arm/gic-hip04.c
@@ -301,6 +301,8 @@ static void __init hip04gic_dist_init(void)
 
     /* Only 1020 interrupts are supported */
     gicv2_info.nr_lines = min(1020U, nr_lines);
+    /* Number of IRQ ids supported */
+    gicv2_info.nr_irq_ids = gicv2_info.nr_lines;
 
     /* Turn on the distributor */
     writel_gicd(GICD_CTL_ENABLE, GICD_CTLR);
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 793dca7..915fd63 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -287,6 +287,8 @@ static void __init gicv2_dist_init(void)
 
     /* Only 1020 interrupts are supported */
     gicv2_info.nr_lines = min(1020U, nr_lines);
+    /* Number of IRQ ids supported */
+    gicv2_info.nr_irq_ids = nr_lines;
 
     /* Turn on the distributor */
     writel_gicd(GICD_CTL_ENABLE, GICD_CTLR);
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index a8082ab..9a7d99f 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -58,6 +58,33 @@ static struct gic_info gicv3_info;
 /* per-cpu re-distributor base */
 DEFINE_PER_CPU(struct rdist, rdist);
 
+/* Enable/Disable ITS support */
+static bool_t its_enable  = 0;
+
+static void __init parse_its_param(char *s)
+{
+    if ( !parse_bool(s) )
+        its_enable = 0;
+}
+
+/* 'msi' command line option to enable/disable ITS */
+custom_param("msi", parse_its_param);
+
+/*
+ * Number of LPIs supported by Xen.
+ *
+ * The LPI identifier starts from 8192. Given that the hardware is
+ * providing the number of identifier bits, supporting LPIs requires at
+ * least 14 bits. This will represent 16384 interrupt ID of which 8192
+ * LPIs. So the minimum of LPIs supported when the hardware supports LPIs
+ * is 8192.
+ */
+#define DEFAULT_NR_LPIS    8192
+static unsigned int nr_lpis;
+
+/* 'nr_lpis' command line option to specify number of LPIs supported by Xen. */
+integer_param("nr_lpis", nr_lpis);
+
 #define GICD                   (gicv3.map_dbase)
 #define GICD_RDIST_BASE        (this_cpu(rdist).rbase)
 #define GICD_RDIST_SGI_BASE    (GICD_RDIST_BASE + SZ_64K)
@@ -529,6 +556,11 @@ static void gicv3_set_irq_properties(struct irq_desc *desc,
     spin_unlock(&gicv3.lock);
 }
 
+static int gicv3_dist_supports_lpis(void)
+{
+    return readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_LPIS_SUPPORTED;
+}
+
 static void __init gicv3_dist_init(void)
 {
     uint32_t type;
@@ -578,6 +610,23 @@ static void __init gicv3_dist_init(void)
 
     /* Only 1020 interrupts are supported */
     gicv3_info.nr_lines = min(1020U, nr_lines);
+
+    /*
+     * Number of IRQ ids supported.
+     * Here we override HW supported number of LPIs and
+     * limit to to LPIs specified in nr_lpis.
+     */
+    if ( its_enable && gicv3_dist_supports_lpis() )
+    {
+        /* Minimum number of lpi supported is 8192 */
+        if ( nr_lpis < DEFAULT_NR_LPIS )
+            nr_lpis = DEFAULT_NR_LPIS;
+
+        gicv3_info.nr_irq_ids = nr_lpis + FIRST_GIC_LPI;
+    }
+    else
+        gicv3_info.nr_irq_ids = gicv3_info.nr_lines;
+
 }
 
 static int gicv3_enable_redist(void)
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 4b46a71..0c43a5b 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -62,6 +62,16 @@ enum gic_version gic_hw_version(void)
    return gic_hw_ops->info->hw_version;
 }
 
+unsigned int gic_nr_irq_ids(void)
+{
+    return gic_hw_ops->info->nr_irq_ids;
+}
+
+bool_t gic_is_lpi(unsigned int irq)
+{
+    return (irq >= FIRST_GIC_LPI && irq < gic_nr_irq_ids());
+}
+
 unsigned int gic_number_lines(void)
 {
     return gic_hw_ops->info->nr_lines;
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 6189ac9..c6e7a8d 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 FIRST_GIC_LPI      8192
 #define MAX_RDIST_COUNT    4
 
 #define GICD_CTLR       (0x000)
@@ -304,6 +305,8 @@ struct gic_info {
     unsigned int maintenance_irq;
     /* Pointer to the device tree node representing the interrupt controller */
     const struct dt_device_node *node;
+    /* Number of IRQ IDs supported */
+    uint32_t nr_irq_ids;
 };
 
 struct gic_hw_operations {
@@ -365,6 +368,8 @@ void register_gic_ops(const struct gic_hw_operations *ops);
 int gic_make_hwdom_dt_node(const struct domain *d,
                            const struct dt_device_node *gic,
                            void *fdt);
+unsigned int gic_nr_irq_ids(void);
+bool_t gic_is_lpi(unsigned int irq);
 
 #endif /* __ASSEMBLY__ */
 #endif
-- 
1.7.9.5

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

* [PATCH v8 10/28] xen/arm: ITS: Implement hw_irq_controller for LPIs
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (8 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 09/28] xen/arm: ITS: Introduce gic_is_lpi helper function vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 11/28] xen/arm: ITS: Enable compilation of physical ITS driver vijayak
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Implement hw_irq_controller callbacks required to
handle LPIs.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Reviewed-by: Julien Grall <julien.grall@citrix.com>
---
v8: - Removed const before hw_irq_controller for lpis
v7: - Split this patch into two. In this patch implement
      only hw_irq_controller callbacks for LPIs.
v6: - Moved this patch #15 in v5 to patch #9
    - Introduce inv command
    - Moved msi_desc helper functions to separate
      "xen/arm: ITS: Introduce msi_desc for LPIs"
    - Exported LPI hw_irq_controller structure and removed
      helper function to access.
v5: - Fixed review comments
    - Exposed gicv3_[host|guest]_irq_end and hook to its
v4: - Implement separate hw_irq_controller for LPIs
    - Drop setting LPI affinity
    - virq and vid are moved under union
    - Introduced inv command handling
    - its_device is stored in irq_desc
---
 xen/arch/arm/gic-v3-its.c         |  119 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c             |    2 +-
 xen/include/asm-arm/gic_v3_defs.h |    2 +
 3 files changed, 122 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index c233950..fa88a75 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -446,6 +446,125 @@ static void its_send_discard(struct its_device *dev, u32 event)
     its_send_single_command(dev->its, &cmd, col);
 }
 
+static void its_flush_and_invalidate_prop(struct irq_desc *desc, const u8 *cfg)
+{
+    struct its_device *its_dev = irqdesc_get_its_device(desc);
+    u32 vid = irqdesc_get_lpi_event(desc);
+
+    ASSERT(vid < its_dev->event_map.nr_lpis);
+
+    /*
+     * 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_and_invalidate_dcache_va_range(cfg, sizeof(*cfg));
+    else
+        dsb(ishst);
+
+    its_send_inv(its_dev, vid);
+}
+
+static void its_set_lpi_state(struct irq_desc *desc, int enable)
+{
+    u8 *cfg;
+
+    ASSERT(spin_is_locked(&its_lock));
+
+    cfg = gic_rdists->prop_page + desc->irq - FIRST_GIC_LPI;
+    if ( enable )
+        *cfg |= LPI_PROP_ENABLED;
+    else
+        *cfg &= ~LPI_PROP_ENABLED;
+
+    its_flush_and_invalidate_prop(desc, cfg);
+}
+
+static void its_irq_enable(struct irq_desc *desc)
+{
+    unsigned long flags;
+
+    ASSERT(spin_is_locked(&desc->lock));
+
+    spin_lock_irqsave(&its_lock, flags);
+    clear_bit(_IRQ_DISABLED, &desc->status);
+    dsb(sy);
+    its_set_lpi_state(desc, 1);
+    spin_unlock_irqrestore(&its_lock, flags);
+}
+
+static void its_irq_disable(struct irq_desc *desc)
+{
+    unsigned long flags;
+
+    ASSERT(spin_is_locked(&desc->lock));
+
+    spin_lock_irqsave(&its_lock, flags);
+    its_set_lpi_state(desc, 0);
+    set_bit(_IRQ_DISABLED, &desc->status);
+    spin_unlock_irqrestore(&its_lock, flags);
+}
+
+static unsigned int its_irq_startup(struct irq_desc *desc)
+{
+    its_irq_enable(desc);
+
+    return 0;
+}
+
+static void its_irq_shutdown(struct irq_desc *desc)
+{
+    its_irq_disable(desc);
+}
+
+static void its_irq_ack(struct irq_desc *desc)
+{
+    /* No ACK -- reading IAR has done this for us */
+}
+
+static void its_host_irq_end(struct irq_desc *desc)
+{
+    /* Lower the priority */
+    gicv3_eoi_irq(desc);
+    /* LPIs does not have active state. Do not deactivate */
+}
+
+static void its_guest_irq_end(struct irq_desc *desc)
+{
+    gicv3_eoi_irq(desc);
+}
+
+static void its_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
+{
+    /*TODO: Yet to support */
+    printk(XENLOG_G_WARNING "ITS: Setting Affinity of LPI is not supported\n");
+
+    return;
+}
+
+hw_irq_controller its_host_lpi_type = {
+    .typename     = "gic-its",
+    .startup      = its_irq_startup,
+    .shutdown     = its_irq_shutdown,
+    .enable       = its_irq_enable,
+    .disable      = its_irq_disable,
+    .ack          = its_irq_ack,
+    .end          = its_host_irq_end,
+    .set_affinity = its_irq_set_affinity,
+};
+
+hw_irq_controller its_guest_lpi_type = {
+    .typename     = "gic-its",
+    .startup      = its_irq_startup,
+    .shutdown     = its_irq_shutdown,
+    .enable       = its_irq_enable,
+    .disable      = its_irq_disable,
+    .ack          = its_irq_ack,
+    .end          = its_guest_irq_end,
+    .set_affinity = its_irq_set_affinity,
+};
+
 /*
  * How we allocate LPIs:
  *
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 9a7d99f..f7cf4e5 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -467,7 +467,7 @@ static void gicv3_mask_irq(struct irq_desc *irqd)
     gicv3_poke_irq(irqd, GICD_ICENABLER);
 }
 
-static void gicv3_eoi_irq(struct irq_desc *irqd)
+void gicv3_eoi_irq(struct irq_desc *irqd)
 {
     /* Lower the priority */
     WRITE_SYSREG32(irqd->irq, ICC_EOIR1_EL1);
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index d675a4d..f02e1aae 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -189,6 +189,8 @@ struct rdist_prop {
 
 DECLARE_PER_CPU(struct rdist, rdist);
 
+void gicv3_eoi_irq(struct irq_desc *irqd);
+
 #endif /* __ASM_ARM_GIC_V3_DEFS_H__ */
 
 /*
-- 
1.7.9.5

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

* [PATCH v8 11/28] xen/arm: ITS: Enable compilation of physical ITS driver
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (9 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 10/28] xen/arm: ITS: Implement hw_irq_controller for LPIs vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 12/28] xen/arm: ITS: Plumb hw_irq_controller for LPIs vijayak
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Enable compilation of pITS driver.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/Makefile |    1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 9982a93..4970641 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -14,6 +14,7 @@ obj-y += domain_build.o
 obj-y += gic.o gic-v2.o
 obj-$(CONFIG_ARM_32) += gic-hip04.o
 obj-$(CONFIG_HAS_GICV3) += gic-v3.o
+obj-$(CONFIG_HAS_GICV3) += gic-v3-its.o
 obj-y += io.o
 obj-y += irq.o
 obj-y += kernel.o
-- 
1.7.9.5

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

* [PATCH v8 12/28] xen/arm: ITS: Plumb hw_irq_controller for LPIs
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (10 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 11/28] xen/arm: ITS: Enable compilation of physical ITS driver vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 13/28] xen/arm: Correct GICD_TYPER register definition typos vijayak
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Zoltan Kiss, Vijaya Kumar K, vijay.kilari

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

Change callbacks gic_host_irq_type and gic_guest_irq_type
to gic_get_host_irq_type and gic_get_guest_irq_type
in gic_hw_operations, which returns hw_irq_controller based
on irq type (SPI or LPI).

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
CC: Zoltan Kiss <zoltan.kiss@huawei.com>
Reviewed-by: Julien Grall <julien.grall@citrix.com>
---
v8: Dropped helper to get hw_irq_controller
---
 xen/arch/arm/gic-hip04.c      |   14 ++++++++++++--
 xen/arch/arm/gic-v2.c         |   14 ++++++++++++--
 xen/arch/arm/gic-v3.c         |   21 +++++++++++++++++++--
 xen/arch/arm/gic.c            |    4 ++--
 xen/include/asm-arm/gic-its.h |    3 +++
 xen/include/asm-arm/gic.h     |    4 ++--
 6 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/gic-hip04.c b/xen/arch/arm/gic-hip04.c
index 9a4091b..193849e 100644
--- a/xen/arch/arm/gic-hip04.c
+++ b/xen/arch/arm/gic-hip04.c
@@ -630,6 +630,16 @@ static hw_irq_controller hip04gic_guest_irq_type = {
     .set_affinity = hip04gic_irq_set_affinity,
 };
 
+static hw_irq_controller *hip04gic_get_host_irq_type(unsigned int irq)
+{
+    return &hip04gic_host_irq_type;
+}
+
+static hw_irq_controller *hip04gic_get_guest_irq_type(unsigned int irq)
+{
+    return &hip04gic_guest_irq_type;
+}
+
 static int __init hip04gic_init(void)
 {
     int res;
@@ -708,8 +718,8 @@ const static struct gic_hw_operations hip04gic_ops = {
     .save_state          = hip04gic_save_state,
     .restore_state       = hip04gic_restore_state,
     .dump_state          = hip04gic_dump_state,
-    .gic_host_irq_type   = &hip04gic_host_irq_type,
-    .gic_guest_irq_type  = &hip04gic_guest_irq_type,
+    .gic_get_host_irq_type   = hip04gic_get_host_irq_type,
+    .gic_get_guest_irq_type  = hip04gic_get_guest_irq_type,
     .eoi_irq             = hip04gic_eoi_irq,
     .deactivate_irq      = hip04gic_dir_irq,
     .read_irq            = hip04gic_read_irq,
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 915fd63..d8de68e 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -630,6 +630,16 @@ static bool_t gicv2_is_aliased(paddr_t cbase, paddr_t csize)
     return ((val_low & 0xfff0fff) == 0x0202043B && val_low == val_high);
 }
 
+static hw_irq_controller *gicv2_get_host_irq_type(unsigned int irq)
+{
+    return &gicv2_host_irq_type;
+}
+
+static hw_irq_controller *gicv2_get_guest_irq_type(unsigned int irq)
+{
+    return &gicv2_guest_irq_type;
+}
+
 static int __init gicv2_init(void)
 {
     int res;
@@ -748,8 +758,8 @@ const static struct gic_hw_operations gicv2_ops = {
     .save_state          = gicv2_save_state,
     .restore_state       = gicv2_restore_state,
     .dump_state          = gicv2_dump_state,
-    .gic_host_irq_type   = &gicv2_host_irq_type,
-    .gic_guest_irq_type  = &gicv2_guest_irq_type,
+    .gic_get_host_irq_type   = gicv2_get_host_irq_type,
+    .gic_get_guest_irq_type  = gicv2_get_guest_irq_type,
     .eoi_irq             = gicv2_eoi_irq,
     .deactivate_irq      = gicv2_dir_irq,
     .read_irq            = gicv2_read_irq,
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index f7cf4e5..45fe624 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -40,6 +40,7 @@
 #include <asm/device.h>
 #include <asm/gic.h>
 #include <asm/gic_v3_defs.h>
+#include <asm/gic-its.h>
 #include <asm/cpufeature.h>
 
 /* Global state */
@@ -1184,6 +1185,22 @@ static const hw_irq_controller gicv3_guest_irq_type = {
     .set_affinity = gicv3_irq_set_affinity,
 };
 
+static hw_irq_controller *gicv3_get_host_irq_type(unsigned int irq)
+{
+    if ( gic_is_lpi(irq) )
+       return &its_host_lpi_type;
+
+    return &gicv3_host_irq_type;
+}
+
+static hw_irq_controller *gicv3_get_guest_irq_type(unsigned int irq)
+{
+    if ( gic_is_lpi(irq) )
+       return &its_guest_lpi_type;
+
+    return &gicv3_guest_irq_type;
+}
+
 static int __init cmp_rdist(const void *a, const void *b)
 {
     const struct rdist_region *l = a, *r = a;
@@ -1352,8 +1369,8 @@ static const struct gic_hw_operations gicv3_ops = {
     .save_state          = gicv3_save_state,
     .restore_state       = gicv3_restore_state,
     .dump_state          = gicv3_dump_state,
-    .gic_host_irq_type   = &gicv3_host_irq_type,
-    .gic_guest_irq_type  = &gicv3_guest_irq_type,
+    .gic_get_host_irq_type   = gicv3_get_host_irq_type,
+    .gic_get_guest_irq_type  = gicv3_get_guest_irq_type,
     .eoi_irq             = gicv3_eoi_irq,
     .deactivate_irq      = gicv3_dir_irq,
     .read_irq            = gicv3_read_irq,
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 0c43a5b..d54bba9 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -128,7 +128,7 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
     ASSERT(test_bit(_IRQ_DISABLED, &desc->status));
     ASSERT(spin_is_locked(&desc->lock));
 
-    desc->handler = gic_hw_ops->gic_host_irq_type;
+    desc->handler = gic_hw_ops->gic_get_host_irq_type(desc->irq);
 
     gic_set_irq_properties(desc, cpu_mask, priority);
 }
@@ -159,7 +159,7 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
          test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) )
         goto out;
 
-    desc->handler = gic_hw_ops->gic_guest_irq_type;
+    desc->handler = gic_hw_ops->gic_get_guest_irq_type(desc->irq);
     set_bit(_IRQ_GUEST, &desc->status);
 
     gic_set_irq_properties(desc, cpumask_of(v_target->processor), priority);
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 7fd7140..fd6ebfb 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -281,6 +281,9 @@ struct its_device {
     struct rb_node          node;
 };
 
+extern const hw_irq_controller its_host_lpi_type;
+extern const hw_irq_controller its_guest_lpi_type;
+
 void irqdesc_set_lpi_event(struct irq_desc *desc, unsigned id);
 unsigned int irqdesc_get_lpi_event(struct irq_desc *desc);
 struct its_device *irqdesc_get_its_device(struct irq_desc *desc);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index c6e7a8d..6b4883a 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -322,10 +322,10 @@ struct gic_hw_operations {
     void (*dump_state)(const struct vcpu *);
 
     /* hw_irq_controller to enable/disable/eoi host irq */
-    hw_irq_controller *gic_host_irq_type;
+    hw_irq_controller *(*gic_get_host_irq_type)(unsigned int irq);
 
     /* hw_irq_controller to enable/disable/eoi guest irq */
-    hw_irq_controller *gic_guest_irq_type;
+    hw_irq_controller *(*gic_get_guest_irq_type)(unsigned int irq);
 
     /* End of Interrupt */
     void (*eoi_irq)(struct irq_desc *irqd);
-- 
1.7.9.5

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

* [PATCH v8 13/28] xen/arm: Correct GICD_TYPER register definition typos
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (11 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 12/28] xen/arm: ITS: Plumb hw_irq_controller for LPIs vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 14/28] xen/arm: ITS: Initialize physical ITS and export lpi support vijayak
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

GICD_TYPER register definitions are defined as GICD_TYPE.
Rename all GICD_TYPE_* as GICD_TYPER_*

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
 xen/arch/arm/gic-hip04.c          |    4 ++--
 xen/arch/arm/gic-v2.c             |    6 +++---
 xen/arch/arm/gic-v3.c             |    2 +-
 xen/arch/arm/vgic-v2.c            |    2 +-
 xen/arch/arm/vgic-v3.c            |    4 ++--
 xen/include/asm-arm/gic.h         |    8 ++++----
 xen/include/asm-arm/gic_v3_defs.h |    2 +-
 7 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/xen/arch/arm/gic-hip04.c b/xen/arch/arm/gic-hip04.c
index 193849e..aa57587 100644
--- a/xen/arch/arm/gic-hip04.c
+++ b/xen/arch/arm/gic-hip04.c
@@ -274,11 +274,11 @@ static void __init hip04gic_dist_init(void)
     writel_gicd(0, GICD_CTLR);
 
     type = readl_gicd(GICD_TYPER);
-    nr_lines = 32 * ((type & GICD_TYPE_LINES) + 1);
+    nr_lines = 32 * ((type & GICD_TYPER_LINES) + 1);
     gic_cpus = 16;
     printk("GIC-HIP04: %d lines, %d cpu%s%s (IID %8.8x).\n",
            nr_lines, gic_cpus, (gic_cpus == 1) ? "" : "s",
-           (type & GICD_TYPE_SEC) ? ", secure" : "",
+           (type & GICD_TYPER_SEC) ? ", secure" : "",
            readl_gicd(GICD_IIDR));
 
     /* Default all global IRQs to level, active low */
diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index d8de68e..daa5a76 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -260,11 +260,11 @@ static void __init gicv2_dist_init(void)
     writel_gicd(0, GICD_CTLR);
 
     type = readl_gicd(GICD_TYPER);
-    nr_lines = 32 * ((type & GICD_TYPE_LINES) + 1);
-    gic_cpus = 1 + ((type & GICD_TYPE_CPUS) >> 5);
+    nr_lines = 32 * ((type & GICD_TYPER_LINES) + 1);
+    gic_cpus = 1 + ((type & GICD_TYPER_CPUS) >> 5);
     printk("GICv2: %d lines, %d cpu%s%s (IID %8.8x).\n",
            nr_lines, gic_cpus, (gic_cpus == 1) ? "" : "s",
-           (type & GICD_TYPE_SEC) ? ", secure" : "",
+           (type & GICD_TYPER_SEC) ? ", secure" : "",
            readl_gicd(GICD_IIDR));
 
     /* Default all global IRQs to level, active low */
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 45fe624..0e1e2f8 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -574,7 +574,7 @@ static void __init gicv3_dist_init(void)
     writel_relaxed(0, GICD + GICD_CTLR);
 
     type = readl_relaxed(GICD + GICD_TYPER);
-    nr_lines = 32 * ((type & GICD_TYPE_LINES) + 1);
+    nr_lines = 32 * ((type & GICD_TYPER_LINES) + 1);
 
     printk("GICv3: %d lines, (IID %8.8x).\n",
            nr_lines, readl_relaxed(GICD + GICD_IIDR));
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 9adb4a9..1f6619d 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -192,7 +192,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         if ( dabt.size != DABT_WORD ) goto bad_width;
         /* No secure world support for guests. */
         vgic_lock(v);
-        typer = ((v->domain->max_vcpus - 1) << GICD_TYPE_CPUS_SHIFT)
+        typer = ( ((v->domain->max_vcpus - 1) << GICD_TYPER_CPUS_SHIFT) )
             | DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32);
         vgic_unlock(v);
 
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 70cf67e..d9b8539 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -919,10 +919,10 @@ 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. */
-        typer = ((ncpus - 1) << GICD_TYPE_CPUS_SHIFT |
+        typer = ((ncpus - 1) << GICD_TYPER_CPUS_SHIFT |
                  DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32));
 
-        typer |= (irq_bits - 1) << GICD_TYPE_ID_BITS_SHIFT;
+        typer |= (irq_bits - 1) << GICD_TYPER_ID_BITS_SHIFT;
 
         *r = vgic_reg32_extract(typer, info);
 
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 6b4883a..bdcb189 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -98,10 +98,10 @@
 /* Register bits */
 #define GICD_CTL_ENABLE 0x1
 
-#define GICD_TYPE_LINES 0x01f
-#define GICD_TYPE_CPUS_SHIFT 5
-#define GICD_TYPE_CPUS  0x0e0
-#define GICD_TYPE_SEC   0x400
+#define GICD_TYPER_LINES 0x01f
+#define GICD_TYPER_CPUS_SHIFT 5
+#define GICD_TYPER_CPUS  0x0e0
+#define GICD_TYPER_SEC   0x400
 
 #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 f02e1aae..50d2056 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -44,7 +44,7 @@
 #define GICC_SRE_EL2_ENEL1           (1UL << 3)
 
 /* Additional bits in GICD_TYPER defined by GICv3 */
-#define GICD_TYPE_ID_BITS_SHIFT 19
+#define GICD_TYPER_ID_BITS_SHIFT     (19)
 
 #define GICD_TYPER_LPIS_SUPPORTED    (1U << 17)
 #define GICD_CTLR_RWP                (1UL << 31)
-- 
1.7.9.5

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

* [PATCH v8 14/28] xen/arm: ITS: Initialize physical ITS and export lpi support
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (12 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 13/28] xen/arm: Correct GICD_TYPER register definition typos vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 15/28] xen/arm: ITS: Add virtual ITS driver vijayak
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Initialize physical ITS if HW supports LPIs.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Rename lpi_support to its_support.
    - Removed its command line parameter.
    - Dropped its_enabled global variable.
v7: - Export lpi support information to vgic-v3 driver from gic-v3.
    - Drop gic_lpi_supported() helper function
    - Add boot param to enable or disable physical ITS
v6: - Updated lpi_supported gic_info member for GICv2 and GICv3
    - Introduced helper gic_lpi_supported() and exported
v5: - Made check of its dt node availability before
      setting lpi_supported flag
---
 xen/arch/arm/gic-v3.c             |   33 +++++++++++++++++++++++++++++++--
 xen/arch/arm/vgic-v3.c            |    5 ++++-
 xen/include/asm-arm/gic_v3_defs.h |    1 +
 xen/include/asm-arm/vgic.h        |    2 +-
 4 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 0e1e2f8..73b2708 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -61,6 +61,8 @@ DEFINE_PER_CPU(struct rdist, rdist);
 
 /* Enable/Disable ITS support */
 static bool_t its_enable  = 0;
+/* Availability of ITS support after successful ITS initialization */
+static bool_t its_enabled = 0;
 
 static void __init parse_its_param(char *s)
 {
@@ -743,6 +745,10 @@ static int gicv3_cpu_init(void)
     if ( gicv3_enable_redist() )
         return -ENODEV;
 
+    /* Give LPIs a spin */
+    if ( gicv3_dist_supports_lpis() )
+        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);
@@ -1346,8 +1352,11 @@ static int __init gicv3_init(void)
                i, r->base, r->base + r->size);
     }
 
-    vgic_v3_setup_hw(dbase, gicv3.rdist_count, gicv3.rdist_regions,
-                     gicv3.rdist_stride);
+    reg = readl_relaxed(GICD + GICD_TYPER);
+
+    gicv3.rdist_data.id_bits = ((reg >> GICD_TYPER_ID_BITS_SHIFT) &
+                                GICD_TYPER_ID_BITS_MASK) + 1;
+
     gicv3_init_v2(node, dbase);
 
     spin_lock_init(&gicv3.lock);
@@ -1355,6 +1364,26 @@ static int __init gicv3_init(void)
     spin_lock(&gicv3.lock);
 
     gicv3_dist_init();
+
+    if ( its_enable && gicv3_dist_supports_lpis() )
+    {
+        /*
+         * LPI support is enabled only if HW supports it and
+         * ITS dt node is available
+         */
+        if ( !its_init(&gicv3.rdist_data) )
+            its_enabled = 1;
+        else
+        {
+            /* ITS initiazation failed. Reset nr_irq_ids to SPIs */
+            gicv3_info.nr_irq_ids = gicv3_info.nr_lines;
+            nr_lpis = 0;
+        }
+    }
+
+    vgic_v3_setup_hw(dbase, gicv3.rdist_count, gicv3.rdist_regions,
+                     gicv3.rdist_stride, its_enabled);
+
     res = gicv3_cpu_init();
     gicv3_hyp_init();
 
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index d9b8539..d59f494 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -50,6 +50,8 @@
 
 static struct {
     bool_t enabled;
+    /* Check if its supported */
+    bool_t its_support;
     /* Distributor interface address */
     paddr_t dbase;
     /* Re-distributor regions */
@@ -61,9 +63,10 @@ static struct {
 void vgic_v3_setup_hw(paddr_t dbase,
                       unsigned int nr_rdist_regions,
                       const struct rdist_region *regions,
-                      uint32_t rdist_stride)
+                      uint32_t rdist_stride, bool_t its_support)
 {
     vgic_v3_hw.enabled = 1;
+    vgic_v3_hw.its_support = its_support;
     vgic_v3_hw.dbase = dbase;
     vgic_v3_hw.nr_rdist_regions = nr_rdist_regions;
     vgic_v3_hw.regions = regions;
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 50d2056..f943461 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -45,6 +45,7 @@
 
 /* Additional bits in GICD_TYPER defined by GICv3 */
 #define GICD_TYPER_ID_BITS_SHIFT     (19)
+#define GICD_TYPER_ID_BITS_MASK      (0x1f)
 
 #define GICD_TYPER_LPIS_SUPPORTED    (1U << 17)
 #define GICD_CTLR_RWP                (1UL << 31)
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index e9ec764..f3b7df5 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -341,7 +341,7 @@ struct rdist_region;
 void vgic_v3_setup_hw(paddr_t dbase,
                       unsigned int nr_rdist_regions,
                       const struct rdist_region *regions,
-                      uint32_t rdist_stride);
+                      uint32_t rdist_stride, bool_t its_support);
 #endif
 
 #endif /* __ASM_ARM_VGIC_H__ */
-- 
1.7.9.5

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

* [PATCH v8 15/28] xen/arm: ITS: Add virtual ITS driver
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (13 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 14/28] xen/arm: ITS: Initialize physical ITS and export lpi support vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 16/28] xen/arm: ITS: Add virtual ITS commands support vijayak
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

This patch introduces virtual ITS driver with following
functionality
 - Introduces helper functions to manage device table and
   ITT table in guest memory
 - Helper function to handle virtual ITS devices assigned
   to domain

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Reviewed-by: Julien Grall <julien.grall@citrix.com>
---
v7: - Moved vits_access_guest_table() from vgic-v3-its.c to vgic.c
      and renamed as vgic_access_guest_memory().
    - Renamed entry paramter in vgic_access_guest_memory() to gipa
    - Introduced new header file vits.h for vITS and moved vits structures
      from gic-its.h to vits.h
v6: - Exported vits_access_guest_memory() api
v5: - Removed RB tree that manages vitual ITS devices
v4: - Rename functions {find,remove,insert}_vits_* to
      vits_{find,remove,insert}.
    - Add common helper function to map and read/write dt
      or vitt table entry.
    - Removed unused code
---
 xen/arch/arm/vgic-v3-its.c   |  123 ++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic.c          |   39 ++++++++++++++
 xen/include/asm-arm/domain.h |    2 +
 xen/include/asm-arm/vits.h   |   68 +++++++++++++++++++++++
 4 files changed, 232 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
new file mode 100644
index 0000000..df54ce5
--- /dev/null
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 Cavium Inc.
+ * Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.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 <xen/bitops.h>
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/irq.h>
+#include <xen/list.h>
+#include <xen/sched.h>
+#include <xen/sizes.h>
+#include <xen/domain_page.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>
+#include <asm/vits.h>
+#include <xen/log2.h>
+
+/* ITS device table helper functions */
+static int vits_vdevice_entry(struct domain *d, uint32_t dev_id,
+                              struct vdevice_table *entry, bool_t set)
+{
+    uint64_t offset;
+    paddr_t dt_entry;
+    const struct vgic_its *vits = d->arch.vgic.vits;
+
+    BUILD_BUG_ON(sizeof(struct vdevice_table) != 16);
+
+    offset = dev_id * sizeof(struct vdevice_table);
+    if ( offset > vits->dt_size )
+    {
+        printk(XENLOG_G_ERR
+               "d%d: vITS: Out of range off 0x%"PRIx64" id 0x%"PRIx32"\n",
+               d->domain_id, offset, dev_id);
+        return -EINVAL;
+    }
+
+    dt_entry = vits->dt_ipa + offset;
+
+    return vgic_access_guest_memory(d, dt_entry, entry,
+                                   sizeof(struct vdevice_table), set);
+}
+
+static int vits_set_vdevice_entry(struct domain *d, uint32_t devid,
+                                  struct vdevice_table *entry)
+{
+    return vits_vdevice_entry(d, devid, entry, 1);
+}
+
+int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
+                           struct vdevice_table *entry)
+{
+    return vits_vdevice_entry(d, devid, entry, 0);
+}
+
+static int vits_vitt_entry(struct domain *d, uint32_t devid,
+                           uint32_t event, struct vitt *entry, bool_t set)
+{
+    struct vdevice_table dt_entry;
+    paddr_t vitt_entry;
+    uint64_t offset;
+
+    BUILD_BUG_ON(sizeof(struct vitt) != 8);
+
+    if ( vits_get_vdevice_entry(d, devid, &dt_entry) )
+    {
+        printk(XENLOG_G_ERR
+               "d%d: vITS: Fail to get vdevice for vdevid 0x%"PRIx32"\n",
+               d->domain_id, devid);
+        return -EINVAL;
+    }
+
+    /* dt_entry has been validated in vits_get_vdevice_entry */
+    offset = event * sizeof(struct vitt);
+    if ( offset > dt_entry.vitt_size )
+    {
+        printk(XENLOG_G_ERR "d%d: vITS: ITT out of range\n", d->domain_id);
+        return -EINVAL;
+    }
+
+    vitt_entry = dt_entry.vitt_ipa + offset;
+
+    return vgic_access_guest_memory(d, vitt_entry, entry,
+                                   sizeof(struct vitt), set);
+}
+
+static int vits_set_vitt_entry(struct domain *d, uint32_t devid,
+                               uint32_t event, struct vitt *entry)
+{
+    return vits_vitt_entry(d, devid, event, entry, 1);
+}
+
+int vits_get_vitt_entry(struct domain *d, uint32_t devid,
+                        uint32_t event, struct vitt *entry)
+{
+    return vits_vitt_entry(d, devid, event, entry, 0);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 8cb3b06..f813931 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -25,6 +25,7 @@
 #include <xen/irq.h>
 #include <xen/sched.h>
 #include <xen/perfc.h>
+#include <xen/domain_page.h>
 
 #include <asm/current.h>
 
@@ -570,6 +571,44 @@ void vgic_free_virq(struct domain *d, unsigned int virq)
     clear_bit(virq, d->arch.vgic.allocated_irqs);
 }
 
+int vgic_access_guest_memory(struct domain *d, paddr_t gipa, void *addr,
+                             uint32_t size, bool_t set)
+{
+    struct page_info *page;
+    uint64_t offset;
+    p2m_type_t p2mt;
+    void *p;
+
+    page = get_page_from_gfn(d, paddr_to_pfn(gipa), &p2mt, P2M_ALLOC);
+    if ( !page )
+    {
+        printk(XENLOG_G_ERR "d%d: vITS: Failed to get table entry\n",
+               d->domain_id);
+        return -EINVAL;
+    }
+
+    if ( !p2m_is_ram(p2mt) )
+    {
+        put_page(page);
+        printk(XENLOG_G_ERR "d%d: vITS: with wrong attributes\n", d->domain_id);
+        return -EINVAL;
+    }
+
+    p = __map_domain_page(page);
+    /* Offset within the mapped page */
+    offset = gipa & ~PAGE_MASK;
+
+    if ( set )
+        memcpy(p + offset, addr, size);
+    else
+        memcpy(addr, p + offset, size);
+
+    unmap_domain_page(p);
+    put_page(page);
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index aa7f283..0ac62d9 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -112,6 +112,8 @@ struct arch_domain
         } rdist_regions[MAX_RDIST_COUNT];
         int nr_regions;                     /* Number of rdist regions */
         uint32_t rdist_stride;              /* Re-Distributor stride */
+        /* Virtual ITS */
+        struct vgic_its *vits;
 #endif
     } vgic;
 
diff --git a/xen/include/asm-arm/vits.h b/xen/include/asm-arm/vits.h
new file mode 100644
index 0000000..6cb5d01
--- /dev/null
+++ b/xen/include/asm-arm/vits.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 Cavium Inc.
+ * Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.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/>.
+ */
+
+#ifndef __ASM_ARM_VITS_H__
+#define __ASM_ARM_VITS_H__
+
+/*
+ * Per domain virtual ITS structure.
+ */
+struct vgic_its
+{
+   /* vITT device table ipa */
+   paddr_t dt_ipa;
+   /* vITT device table size */
+   uint64_t dt_size;
+};
+
+/*
+ * struct vdevice_table and struct vitt are typically stored in memory
+ * which has been provided by the guest out of its own address space
+ * and which remains accessible to the guest.
+ *
+ * Therefore great care _must_ be taken when accessing an entry in
+ * either table to validate the sanity of any values which are used.
+ */
+struct vdevice_table {
+    uint64_t vitt_ipa;
+    uint32_t vitt_size;
+    uint32_t padding;
+};
+
+struct vitt {
+    uint16_t valid:1;
+    uint16_t pad:15;
+    uint16_t vcollection;
+    uint32_t vlpi;
+};
+
+int vgic_access_guest_memory(struct domain *d, paddr_t gipa, void *addr,
+                             uint32_t size, bool_t set);
+int vits_get_vitt_entry(struct domain *d, uint32_t devid, uint32_t event,
+                        struct vitt *entry);
+int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
+                           struct vdevice_table *entry);
+
+#endif /* __ASM_ARM_VITS_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] 31+ messages in thread

* [PATCH v8 16/28] xen/arm: ITS: Add virtual ITS commands support
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (14 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 15/28] xen/arm: ITS: Add virtual ITS driver vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 17/28] xen/arm: ITS: Add GITS registers emulation vijayak
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Add Virtual ITS command processing support to Virtual ITS driver

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Reviewed-by: Julien Grall <julien.grall@citrix.com>
---
v8: - Fixed coding styles
v7: - Moved is_valid_collection() declaration to vits.h
    - Added check for number of vcpus of a domain in
      vits_domain_init()
    - Moved changes in gic-its.h to vits.h
    - vits_process_cmd() is made static
    - Fixed coding styles
v6: - Updated printk to use correct PRI*
    - Moved vits_get_max_collection and is_valid_collection
      helper to this patch
    - Added vits_domain_free()
    - Few more review comments
v5: - Rename vgic_its_*() to vits_*()
v4: - Use helper function to read from command queue
    - Add MOVALL
    - Removed check for entry in device in domain RB-tree
---
 xen/arch/arm/vgic-v3-its.c    |  432 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic-its.h |    2 +
 xen/include/asm-arm/vits.h    |   14 ++
 3 files changed, 448 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index df54ce5..22c8a4c 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -26,6 +26,7 @@
 #include <asm/device.h>
 #include <asm/mmio.h>
 #include <asm/io.h>
+#include <asm/atomic.h>
 #include <asm/gic_v3_defs.h>
 #include <asm/gic.h>
 #include <asm/vgic.h>
@@ -33,6 +34,49 @@
 #include <asm/vits.h>
 #include <xen/log2.h>
 
+//#define DEBUG_ITS
+
+#ifdef DEBUG_ITS
+# define DPRINTK(fmt, args...) dprintk(XENLOG_DEBUG, fmt, ##args)
+#else
+# define DPRINTK(fmt, args...) do {} while ( 0 )
+#endif
+
+#ifdef DEBUG_ITS
+static void dump_cmd(const its_cmd_block *cmd)
+{
+    printk("VITS:CMD[0] = 0x%lx CMD[1] = 0x%lx CMD[2] = 0x%lx CMD[3] = 0x%lx\n",
+           cmd->bits[0], cmd->bits[1], cmd->bits[2], cmd->bits[3]);
+}
+#else
+static void dump_cmd(const its_cmd_block *cmd) { }
+#endif
+
+static inline uint16_t vits_get_max_collections(struct domain *d)
+{
+    /*
+     * ITS only supports up to 256 collections without
+     * provisioning external memory. As per vITS design, number of
+     * vCPUS should not exceed max number of collections.
+     */
+    ASSERT(d->max_vcpus < 256);
+
+    /*
+     * Each collection corresponds to one CPU(vCPU). Collections are
+     * used to move interrupts from one CPU to another. The ITS
+     * mandates to implement N + 1 collections where N is the number of
+     * processor on the platform (i.e max number of VCPUs for a given
+     * guest).
+     * Refer to PRD03-GENC-010745 24 section 4.9.15.
+     */
+    return (d->max_vcpus + 1);
+}
+
+bool_t is_valid_collection(struct domain *d, uint16_t col)
+{
+    return (col <= vits_get_max_collections(d));
+}
+
 /* ITS device table helper functions */
 static int vits_vdevice_entry(struct domain *d, uint32_t dev_id,
                               struct vdevice_table *entry, bool_t set)
@@ -113,6 +157,394 @@ int vits_get_vitt_entry(struct domain *d, uint32_t devid,
     return vits_vitt_entry(d, devid, event, entry, 0);
 }
 
+static int vits_process_sync(struct vcpu *v, struct vgic_its *vits,
+                             its_cmd_block *virt_cmd)
+{
+    /* Ignored */
+    DPRINTK("%pv: vITS: SYNC: ta 0x%"PRIx32" \n", v, virt_cmd->sync.target_addr);
+
+    return 0;
+}
+
+static int vits_process_mapvi(struct vcpu *v, struct vgic_its *vits,
+                              its_cmd_block *virt_cmd)
+{
+    struct vitt entry;
+    struct domain *d = v->domain;
+    uint16_t vcol_id;
+    uint8_t cmd;
+    uint32_t vid, dev_id, event;
+
+    vcol_id = virt_cmd->mapvi.col;
+    vid = virt_cmd->mapvi.phy_id;
+    cmd = virt_cmd->mapvi.cmd;
+    dev_id = virt_cmd->mapvi.devid;
+
+    DPRINTK("%pv: vITS: MAPVI: dev 0x%"PRIx32" vcol %"PRIu16" vid %"PRIu32"\n",
+             v, dev_id, vcol_id, vid);
+
+    entry.valid = true;
+    entry.vcollection = vcol_id;
+    entry.vlpi = vid;
+
+    if ( cmd == GITS_CMD_MAPI )
+        vits_set_vitt_entry(d, dev_id, vid, &entry);
+    else
+    {
+        event = virt_cmd->mapvi.event;
+        vits_set_vitt_entry(d, dev_id, event, &entry);
+    }
+
+    return 0;
+}
+
+static int vits_process_movi(struct vcpu *v, struct vgic_its *vits,
+                             its_cmd_block *virt_cmd)
+{
+    struct vitt entry;
+    struct domain *d = v->domain;
+    uint32_t dev_id, event;
+    uint16_t vcol_id;
+
+    vcol_id = virt_cmd->movi.col;
+    event = virt_cmd->movi.event;
+    dev_id = virt_cmd->movi.devid;
+
+    DPRINTK("%pv vITS: MOVI: dev_id 0x%"PRIx32" vcol %"PRIu16" event %"PRIu32"\n",
+            v, dev_id, vcol_id, event);
+
+    if ( vits_get_vitt_entry(d, dev_id, event, &entry) )
+        return -EINVAL;
+
+    entry.vcollection = vcol_id;
+
+    if ( vits_set_vitt_entry(d, dev_id, event, &entry) )
+        return -EINVAL;
+
+    return 0;
+}
+
+static int vits_process_movall(struct vcpu *v, struct vgic_its *vits,
+                               its_cmd_block *virt_cmd)
+{
+    /* Ignored */
+    DPRINTK("%pv: vITS: MOVALL: ta1 0x%"PRIx32" ta2 0x%"PRIx32" \n",
+            v, virt_cmd->movall.target_addr1, virt_cmd->movall.target_addr2);
+
+    return 0;
+}
+
+static int vits_process_discard(struct vcpu *v, struct vgic_its *vits,
+                                its_cmd_block *virt_cmd)
+{
+    struct vitt entry;
+    struct domain *d = v->domain;
+    uint32_t event, dev_id;
+
+    event = virt_cmd->discard.event;
+    dev_id = virt_cmd->discard.devid;
+
+    DPRINTK("%pv vITS: DISCARD: dev_id 0x%"PRIx32" id %"PRIu32"\n",
+            v, virt_cmd->discard.devid, event);
+
+    if ( vits_get_vitt_entry(d, dev_id, event, &entry) )
+        return -EINVAL;
+
+    entry.valid = false;
+
+    if ( vits_set_vitt_entry(d, dev_id, event, &entry) )
+        return -EINVAL;
+
+    return 0;
+}
+
+static int vits_process_inv(struct vcpu *v, struct vgic_its *vits,
+                            its_cmd_block *virt_cmd)
+{
+    /* Ignored */
+    DPRINTK("%pv vITS: INV: dev_id 0x%"PRIx32" id %"PRIu32"\n",
+            v, virt_cmd->inv.devid, virt_cmd->inv.event);
+
+    return 0;
+}
+
+static int vits_process_clear(struct vcpu *v, struct vgic_its *vits,
+                              its_cmd_block *virt_cmd)
+{
+    /* Ignored */
+    DPRINTK("%pv: vITS: CLEAR: dev_id 0x%"PRIx32" id %"PRIu32"\n",
+            v, virt_cmd->clear.devid, virt_cmd->clear.event);
+
+    return 0;
+}
+
+static int vits_process_invall(struct vcpu *v, struct vgic_its *vits,
+                               its_cmd_block *virt_cmd)
+{
+    /* Ignored */
+    DPRINTK("%pv: vITS: INVALL: vCID %"PRIu16"\n", v, virt_cmd->invall.col);
+
+    return 0;
+}
+
+static int vits_process_int(struct vcpu *v, struct vgic_its *vits,
+                            its_cmd_block *virt_cmd)
+{
+    uint32_t event, dev_id;
+
+    event = virt_cmd->int_cmd.cmd;
+    dev_id = virt_cmd->int_cmd.devid;
+
+    DPRINTK("%pv: vITS: INT: Device 0x%"PRIx32" id %"PRIu32"\n",
+            v, dev_id, event);
+
+    /* TODO: Inject LPI */
+
+    return 0;
+}
+
+static int vits_add_device(struct vcpu *v, struct vgic_its *vits,
+                           its_cmd_block *virt_cmd)
+{
+    struct domain *d = v->domain;
+    struct vdevice_table dt_entry;
+    uint32_t dev_id = virt_cmd->mapd.devid;
+
+    DPRINTK("%pv: vITS:Add dev 0x%"PRIx32" ipa = 0x%"PRIx64" size %"PRIu32"\n",
+            v, dev_id, (u64)virt_cmd->mapd.itt << MAPC_ITT_IPA_SHIFT,
+            virt_cmd->mapd.size);
+
+    if ( virt_cmd->mapd.valid )
+    {
+        /* itt field is 40 bit. extract 48 bit address by shifting */
+        dt_entry.vitt_ipa = virt_cmd->mapd.itt << MAPC_ITT_IPA_SHIFT;
+        dt_entry.vitt_size = (1 << (virt_cmd->mapd.size + 1)) *
+                              sizeof(struct vitt);
+    }
+    else
+    {
+        dt_entry.vitt_ipa = INVALID_PADDR;
+        dt_entry.vitt_size = 0;
+    }
+
+    if ( vits_set_vdevice_entry(d, dev_id, &dt_entry) )
+        return -EINVAL;
+
+    return 0;
+}
+
+static int vits_process_mapc(struct vcpu *v, struct vgic_its *vits,
+                             its_cmd_block *virt_cmd)
+{
+    uint16_t vcol_id = virt_cmd->mapc.col;
+    uint64_t vta = virt_cmd->mapc.ta;
+
+    DPRINTK("%pv: vITS: MAPC: vCID %"PRIu16" vTA 0x%"PRIx64" valid %"PRIu8"\n",
+            v, vcol_id, vta, virt_cmd->mapc.valid);
+
+    if ( !is_valid_collection(v->domain, vcol_id) )
+        return -EINVAL;
+
+    if ( virt_cmd->mapc.valid )
+    {
+        if ( vta > v->domain->max_vcpus )
+            return -EINVAL;
+        vits->collections[vcol_id].target_address = vta;
+    }
+    else
+        vits->collections[vcol_id].target_address = INVALID_PADDR;
+
+    return 0;
+}
+
+#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 vits_parse_its_command(struct vcpu *v, struct vgic_its *vits,
+                                  its_cmd_block *virt_cmd)
+{
+    uint8_t cmd = virt_cmd->hdr.cmd;
+    int ret;
+
+    DPRINTK("%pv: vITS: Received cmd %s (0x%"PRIx8")\n", v, cmd_str[cmd], cmd);
+    dump_cmd(virt_cmd);
+
+    switch ( cmd )
+    {
+    case GITS_CMD_MAPD:
+        ret = vits_add_device(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_MAPC:
+        ret = vits_process_mapc(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_MAPI:
+        /* MAPI is same as MAPVI */
+    case GITS_CMD_MAPVI:
+        ret = vits_process_mapvi(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_MOVI:
+        ret = vits_process_movi(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_MOVALL:
+        ret = vits_process_movall(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_DISCARD:
+        ret = vits_process_discard(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_INV:
+        ret = vits_process_inv(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_INVALL:
+        ret = vits_process_invall(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_INT:
+        ret = vits_process_int(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_CLEAR:
+        ret = vits_process_clear(v, vits, virt_cmd);
+        break;
+    case GITS_CMD_SYNC:
+        ret = vits_process_sync(v, vits, virt_cmd);
+        break;
+    default:
+       dprintk(XENLOG_G_ERR, "%pv: vITS: Unhandled command cmd %"PRIu8"\n",
+               v, cmd);
+       return 1;
+    }
+
+    if ( ret )
+    {
+       dprintk(XENLOG_G_ERR, "%pv: vITS: Failed to handle cmd %"PRIu8"\n",
+               v, cmd);
+       return 1;
+    }
+
+    return 0;
+}
+
+static int vits_read_virt_cmd(struct vcpu *v, struct vgic_its *vits,
+                              its_cmd_block *virt_cmd)
+{
+    paddr_t maddr;
+    struct domain *d = v->domain;
+    int ret;
+
+    ASSERT(spin_is_locked(&vits->lock));
+
+    if ( !(vits->cmd_base & GITS_CBASER_VALID) )
+    {
+        dprintk(XENLOG_G_ERR, "%pv: vITS: Invalid CBASER\n", v);
+        return 0;
+    }
+
+    /* Get command queue offset */
+    maddr = (vits->cmd_base & GITS_CBASER_PA_MASK) +
+             atomic_read(&vits->cmd_read);
+
+    DPRINTK("%pv: vITS: Mapping CMD Q maddr 0x%"PRIx64" read 0x%"PRIx32"\n",
+            v, maddr, atomic_read(&vits->cmd_read));
+
+    ret = vgic_access_guest_memory(d, maddr, (void *)virt_cmd,
+                                   sizeof(its_cmd_block), 0);
+    if ( ret )
+    {
+        dprintk(XENLOG_G_ERR,
+                "%pv: vITS: Failed to get command page @page 0x%"PRIx32"\n",
+                v, atomic_read(&vits->cmd_read));
+        return -EINVAL;
+    }
+
+    atomic_add(sizeof(its_cmd_block), &vits->cmd_read);
+    if ( atomic_read(&vits->cmd_read) == vits->cmd_qsize )
+    {
+         DPRINTK("%pv: vITS: Reset read @ 0x%"PRIx32" qsize 0x%"PRIx64"\n",
+                 v, atomic_read(&vits->cmd_read), vits->cmd_qsize);
+
+         atomic_set(&vits->cmd_read, 0);
+    }
+
+    return 0;
+}
+
+static int vits_process_cmd(struct vcpu *v, struct vgic_its *vits)
+{
+    its_cmd_block virt_cmd;
+
+    ASSERT(spin_is_locked(&vits->lock));
+
+    do {
+        if ( vits_read_virt_cmd(v, vits, &virt_cmd) )
+            goto err;
+        if ( vits_parse_its_command(v, vits, &virt_cmd) )
+            goto err;
+    } while ( vits->cmd_write != atomic_read(&vits->cmd_read) );
+
+    DPRINTK("%pv: vITS: read @ 0x%"PRIx32" write @ 0x%"PRIx64"\n",
+            v, atomic_read(&vits->cmd_read),
+            vits->cmd_write);
+
+    return 1;
+err:
+    dprintk(XENLOG_G_ERR, "%pv: vITS: Failed to process guest cmd\n", v);
+    domain_crash_synchronous();
+
+    return 0;
+}
+
+int vits_domain_init(struct domain *d)
+{
+    struct vgic_its *vits;
+    int i;
+
+    if ( d->max_vcpus >= 256 )
+    {
+        printk(XENLOG_G_ERR
+               "vITS: Cannot support guest with >= 256 vCPUs for domaind %d\n",
+               d->domain_id);
+        return -ENXIO;
+    }
+
+    ASSERT(is_hardware_domain(d));
+
+    d->arch.vgic.vits = xzalloc(struct vgic_its);
+    if ( !d->arch.vgic.vits )
+        return -ENOMEM;
+
+    vits = d->arch.vgic.vits;
+
+    spin_lock_init(&vits->lock);
+
+    vits->collections = xzalloc_array(struct its_collection,
+                                      vits_get_max_collections(d));
+    if ( !vits->collections )
+        return -ENOMEM;
+
+    for ( i = 0; i < vits_get_max_collections(d); i++ )
+        vits->collections[i].target_address = INVALID_PADDR;
+
+    return 0;
+}
+
+void vits_domain_free(struct domain *d)
+{
+   xfree(d->arch.vgic.vits->collections);
+   xfree(d->arch.vgic.vits);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index fd6ebfb..0faa2fa 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -59,6 +59,7 @@
 #define GITS_CBASER_InnerShareable      (1UL << 10)
 #define GITS_CBASER_SHAREABILITY_MASK   (3UL << 10)
 #define GITS_CBASER_CACHEABILITY_MASK   (7UL << 59)
+#define GITS_CBASER_PA_MASK             (0xfffffffff000UL)
 
 #define GITS_BASER_NR_REGS              8
 
@@ -169,6 +170,7 @@ typedef union {
         u64 res4;
     } invall;
     struct __packed {
+#define MAPC_ITT_IPA_SHIFT 8
         u64 cmd:8;
         u64 res1:56;
         u64 res2;
diff --git a/xen/include/asm-arm/vits.h b/xen/include/asm-arm/vits.h
index 6cb5d01..295cce4 100644
--- a/xen/include/asm-arm/vits.h
+++ b/xen/include/asm-arm/vits.h
@@ -23,10 +23,21 @@
  */
 struct vgic_its
 {
+   spinlock_t lock;
+   /* Command queue base */
+   paddr_t cmd_base;
+   /* Command queue write pointer */
+   paddr_t cmd_write;
+   /* Command queue read pointer */
+   atomic_t cmd_read;
+   /* Command queue size */
+   unsigned long cmd_qsize;
    /* vITT device table ipa */
    paddr_t dt_ipa;
    /* vITT device table size */
    uint64_t dt_size;
+   /* collections mapped */
+   struct its_collection *collections;
 };
 
 /*
@@ -50,6 +61,9 @@ struct vitt {
     uint32_t vlpi;
 };
 
+bool_t is_valid_collection(struct domain *d, uint16_t col);
+int vits_domain_init(struct domain *d);
+void vits_domain_free(struct domain *d);
 int vgic_access_guest_memory(struct domain *d, paddr_t gipa, void *addr,
                              uint32_t size, bool_t set);
 int vits_get_vitt_entry(struct domain *d, uint32_t devid, uint32_t event,
-- 
1.7.9.5

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

* [PATCH v8 17/28] xen/arm: ITS: Add GITS registers emulation
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (15 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 16/28] xen/arm: ITS: Add virtual ITS commands support vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 18/28] xen/arm: ITS: Export ITS info to Virtual ITS vijayak
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Emulate GITS* registers

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Fixed GITS_BASER0 value.
    - Added comments for GITS_BASER0.
    - Support 32/64 bit access for GITS_BASER0 and GITS_CBASER.
    - s/vits->ctrl/vits->ctlr/
    - Used VREG{64,32} and VRANGE{64,32} macros
v7: - Fixed wrong usage of vgic_regN* helpers
    - coding styles and comments
    - GITS_BASER0 is always overwritten with new value every time
      it is updated.
v6: - Removed unrelated code of this patch
    - Used vgic_regN_{read,write}
v4: - Removed GICR register emulation
---
 xen/arch/arm/vgic-v3-its.c        |  332 +++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic-v3.c            |    9 -
 xen/include/asm-arm/gic-its.h     |    8 +
 xen/include/asm-arm/gic_v3_defs.h |   14 ++
 xen/include/asm-arm/vgic.h        |    9 +
 xen/include/asm-arm/vits.h        |   27 ++-
 6 files changed, 388 insertions(+), 11 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 22c8a4c..bdcd9f1 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -33,9 +33,27 @@
 #include <asm/gic-its.h>
 #include <asm/vits.h>
 #include <xen/log2.h>
+#include <asm/vgic-emul.h>
 
 //#define DEBUG_ITS
 
+/* 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)
+
+/*
+ * GITS_BASER0 is used to allocate memory for the Device table.
+ * Some of the fields GITS_BASER0.Type and GITS_BASER0.Entry_size
+ * are read-only. Initialize GITS_BASER0_Type = 1 ( Device )
+ * and GITS_BASER0.Entry_size = size of vitt structure (vitt)-1.
+ */
+#define GITS_BASER0_INIT_VAL         ((1UL << GITS_BASER_TYPE_SHIFT) | \
+                                      ((sizeof(struct vitt) - 1) <<    \
+                                      GITS_BASER_ENTRY_SIZE_SHIFT))
+
 #ifdef DEBUG_ITS
 # define DPRINTK(fmt, args...) dprintk(XENLOG_DEBUG, fmt, ##args)
 #else
@@ -505,6 +523,307 @@ err:
     return 0;
 }
 
+static inline void vits_spin_lock(struct vgic_its *vits)
+{
+    spin_lock(&vits->lock);
+}
+
+static inline void vits_spin_unlock(struct vgic_its *vits)
+{
+    spin_unlock(&vits->lock);
+}
+
+static int vgic_v3_gits_mmio_read(struct vcpu *v, mmio_info_t *info,
+                                  register_t *r, void *priv)
+{
+    struct vgic_its *vits = v->domain->arch.vgic.vits;
+    struct hsr_dabt dabt = info->dabt;
+    uint64_t val;
+    uint32_t gits_reg;
+
+    gits_reg = info->gpa - vits->gits_base;
+    DPRINTK("%pv: vITS: GITS_MMIO_READ offset 0x%"PRIx32"\n", v, gits_reg);
+
+    switch ( gits_reg )
+    {
+    case VREG32(GITS_CTLR):
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        vits_spin_lock(vits);
+        *r = vgic_reg32_extract(vits->ctlr, info);
+        vits_spin_unlock(vits);
+        return 1;
+    case VREG32(GITS_IIDR):
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GICV3_GICD_IIDR_VAL, info);
+        return 1;
+    case VREG64(GITS_TYPER):
+        /*
+         * GITS_TYPER.HCC = max_vcpus + 1 (max collection supported)
+         * GITS_TYPER.Devbits = HW supported Devbits size
+         * GITS_TYPER.IDbits = HW supported IDbits size
+         * GITS_TYPER.PTA = 0 (Target addresses are linear processor numbers)
+         * GITS_TYPER.ITTSize = Size of struct vitt
+         * GITS_TYPER.Physical = 1
+         */
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        val = ((vits_get_max_collections(v->domain) << GITS_TYPER_HCC_SHIFT ) |
+               ((vits_hw.devID_bits - 1) << GITS_TYPER_DEVBITS_SHIFT)         |
+               ((vits_hw.eventID_bits - 1) << GITS_TYPER_IDBITS_SHIFT)        |
+               ((sizeof(struct vitt) - 1) << GITS_TYPER_ITT_SIZE_SHIFT)       |
+                 GITS_TYPER_PHYSICAL_LPIS);
+        *r = vgic_reg64_extract(val, info);
+        return 1;
+    case 0x0010 ... 0x007c:
+    case 0xc000 ... 0xffcc:
+        /* Implementation defined -- read ignored */
+        goto read_as_zero;
+    case VREG64(GITS_CBASER):
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        vits_spin_lock(vits);
+        if ( vits->ctlr & GITS_CTLR_ENABLE )
+            *r = vgic_reg64_extract(vits->cmd_base, info);
+        else
+            *r = vgic_reg64_extract(vits->cmd_base_save, info);
+        vits_spin_unlock(vits);
+        return 1;
+    case VREG64(GITS_CWRITER):
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        vits_spin_lock(vits);
+        *r = vgic_reg64_extract(vits->cmd_write & 0xfffe0, info);
+        vits_spin_unlock(vits);
+        return 1;
+    case VREG64(GITS_CREADR):
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        *r = vgic_reg64_extract(atomic_read(&vits->cmd_read) & 0xfffe0, info);
+        return 1;
+    case 0x0098 ... 0x009c:
+    case 0x00a0 ... 0x00fc:
+    case 0x0140 ... 0xbffc:
+        /* Reserved -- read ignored */
+        goto read_as_zero;
+    case VREG64(GITS_BASER0):
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        vits_spin_lock(vits);
+        if ( vits->ctlr & GITS_CTLR_ENABLE )
+            *r = vgic_reg64_extract(vits->baser0, info);
+        else
+            *r = vgic_reg64_extract(vits->baser0_save, info);
+        vits_spin_unlock(vits);
+        return 1;
+    case VRANGE64(GITS_BASER1, GITS_BASERN):
+        goto read_as_zero_64;
+    case VREG32(GITS_PIDR0):
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GITS_PIDR0_VAL, info);
+        return 1;
+    case VREG32(GITS_PIDR1):
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GITS_PIDR1_VAL, info);
+        return 1;
+    case VREG32(GITS_PIDR2):
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GITS_PIDR2_VAL, info);
+        return 1;
+    case VREG32(GITS_PIDR3):
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GITS_PIDR3_VAL, info);
+        return 1;
+    case VREG32(GITS_PIDR4):
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        *r = vgic_reg32_extract(GITS_PIDR4_VAL, info);
+        return 1;
+    case VRANGE32(GITS_PIDR5 ,GITS_PIDR7):
+        goto read_as_zero_32;
+   default:
+        dprintk(XENLOG_G_ERR,
+                "%pv: vITS: unhandled read r%d offset 0x%#08"PRIx32"\n",
+                v, dabt.reg, gits_reg);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_G_ERR,
+            "%pv: vITS: bad read width %d r%d offset 0x%#08"PRIx32"\n",
+            v, dabt.size, dabt.reg, gits_reg);
+    domain_crash_synchronous();
+    return 0;
+
+read_as_zero_64:
+    if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+    *r = 0;
+    return 1;
+read_as_zero_32:
+    if ( dabt.size != DABT_WORD ) goto bad_width;
+read_as_zero:
+    *r = 0;
+    return 1;
+}
+
+/*
+ * GITS_BASER.Type[58:56], GITS_BASER.Entry_size[55:48]
+ * and GITS_BASER.Shareability[11:10] are read-only,
+ * Only flat table is supported. So GITS_BASER.Indirect[62]
+ * is RAZ/WI.
+ * Mask those fields while emulating GITS_BASER reg.
+ * Shareability is set to 0x0 (Reserved) which is fixed.
+ * TODO: Support shareability as fixed value is deprecated
+ */
+#define GITS_BASER_MASK  (~((0x7UL << GITS_BASER_TYPE_SHIFT)       | \
+                         (0x1UL << GITS_BASER_INDIRECT_SHIFT)      | \
+                         (0xffUL << GITS_BASER_ENTRY_SIZE_SHIFT)   | \
+                         (0x3UL << GITS_BASER_SHAREABILITY_SHIFT)))
+
+static int vgic_v3_gits_mmio_write(struct vcpu *v, mmio_info_t *info,
+                                   register_t r, void *priv)
+{
+    struct vgic_its *vits = v->domain->arch.vgic.vits;
+    struct hsr_dabt dabt = info->dabt;
+    int ret;
+    uint32_t gits_reg, sz, psz;
+    uint64_t val;
+
+    gits_reg = info->gpa - vits->gits_base;
+
+    DPRINTK("%pv: vITS: GITS_MMIO_WRITE offset 0x%"PRIx32"\n", v, gits_reg);
+    switch ( gits_reg )
+    {
+    case VREG32(GITS_CTLR):
+    {
+        uint32_t gits_ctlr;
+
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        vits_spin_lock(vits);
+        /*
+         * vITS is always quiescent, has no translations in progress and
+         * completed all operations. So set quiescent by default.
+         */
+        gits_ctlr = vits->ctlr;
+        vgic_reg32_update(&vits->ctlr,
+                         (r & GITS_CTLR_ENABLE) | GITS_CTLR_QUIESCENT, info);
+        /* If no change in GITS_CTRL.Enabled. Just return */ 
+        if ( !((gits_ctlr ^ vits->ctlr) && (vits->ctlr & GITS_CTLR_ENABLE)) )
+        {
+            vits_spin_unlock(vits);
+            return 1;
+        }
+        /*
+         * On GITS_CTLR.Enabled = 1, update cmdbaser and baser0 
+         * with cmd_base_save and baser0_save, if they are changed.
+         */
+        if ( vits->cmd_base_save ^ vits->cmd_base )
+        {
+            vits->cmd_base = vits->cmd_base_save;
+            if ( vits->cmd_base & GITS_BASER_VALID )
+            {
+                val = ((vits->cmd_base & GITS_BASER_PAGES_MASK_VAL) + 1) *
+                        SZ_4K;
+                vits->cmd_qsize = val;
+                atomic_set(&vits->cmd_read, 0);
+            }
+        }
+        if ( vits->baser0_save ^ vits->baser0 )
+        {
+            vits->baser0 = vits->baser0_save;
+            vits->dt_ipa = vits->baser0 & GITS_BASER_PA_MASK;
+            psz = (vits->baser0 >> GITS_BASER_PAGE_SIZE_SHIFT) &
+                   GITS_BASER_PAGE_SIZE_MASK_VAL;
+            if ( psz == GITS_BASER_PAGE_SIZE_4K_VAL )
+                sz = 4;
+            else if ( psz == GITS_BASER_PAGE_SIZE_16K_VAL )
+                sz = 16;
+            else
+                /* 0x11 and 0x10 are treated as 64K size */
+                sz = 64;
+
+            vits->dt_size = (vits->baser0 & GITS_BASER_PAGES_MASK_VAL) * sz *
+                             SZ_1K;
+        }
+        vits_spin_unlock(vits);
+        return 1;
+    }
+    case VREG32(GITS_IIDR):
+        /* RO -- write ignored */
+        goto write_ignore;
+    case VREG64(GITS_TYPER):
+        /* RO -- write ignored */
+        goto write_ignore;
+    case 0x0010 ... 0x007c:
+    case 0xc000 ... 0xffcc:
+        /* Implementation defined -- write ignored */
+        goto write_ignore;
+    case VREG64(GITS_CBASER):
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        vits_spin_lock(vits);
+        /* RO -- write ignored, if GITS_CTLR.Enabled = 1 */
+        if ( !(vits->ctlr & GITS_CTLR_ENABLE) )
+            vgic_reg64_update(&vits->cmd_base_save, r, info);
+        vits_spin_unlock(vits);
+        return 1;
+    case VREG64(GITS_CWRITER):
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        vits_spin_lock(vits);
+        /* Only Bits[19:5] are writable */
+        vgic_reg64_update(&vits->cmd_write, (r & 0xfffe0), info);
+        ret = 1;
+        /* CWRITER should be within command queue range */
+        if ( (vits->ctlr & GITS_CTLR_ENABLE) &&
+             (vits->cmd_write < vits->cmd_qsize) )
+            ret = vits_process_cmd(v, vits);
+        vits_spin_unlock(vits);
+        return ret;
+    case VREG64(GITS_CREADR):
+        /* RO -- write ignored */
+        goto write_ignore_64;
+    case 0x0098 ... 0x009c:
+    case 0x00a0 ... 0x00fc:
+    case 0x0140 ... 0xbffc:
+        /* Reserved -- write ignored */
+        goto write_ignore;
+    case VREG64(GITS_BASER0):
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        vits_spin_lock(vits);
+        /* RO -- write ignored if GITS_CTLR.Enable = 1 */
+        if ( !(vits->ctlr & GITS_CTLR_ENABLE) )
+        {
+            val = GITS_BASER0_INIT_VAL | (r & GITS_BASER_MASK);
+            vgic_reg64_update(&vits->baser0_save, val, info);
+        }
+        vits_spin_unlock(vits);
+        return 1;
+    case VRANGE64(GITS_BASER1, GITS_BASERN):
+        goto write_ignore_64;
+    case VRANGE32(GITS_PIDR7, GITS_PIDR0):
+        /* RO -- write ignored */
+        goto write_ignore_32;
+   default:
+        dprintk(XENLOG_G_ERR,
+                "%pv vITS: unhandled write r%d offset 0x%#08"PRIx32"\n",
+                v, dabt.reg, gits_reg);
+        return 0;
+    }
+
+bad_width:
+    dprintk(XENLOG_G_ERR,
+            "%pv: vITS: bad write width %d r%d offset 0x%#08"PRIx32"\n",
+            v, dabt.size, dabt.reg, gits_reg);
+    domain_crash_synchronous();
+    return 0;
+
+write_ignore_64:
+    if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+    return 1;
+write_ignore_32:
+    if ( dabt.size != DABT_WORD ) goto bad_width;
+    return 1;
+write_ignore:
+    return 1;
+}
+
+static const struct mmio_handler_ops vgic_gits_mmio_handler = {
+    .read  = vgic_v3_gits_mmio_read,
+    .write = vgic_v3_gits_mmio_write,
+};
+
 int vits_domain_init(struct domain *d)
 {
     struct vgic_its *vits;
@@ -536,6 +855,19 @@ int vits_domain_init(struct domain *d)
     for ( i = 0; i < vits_get_max_collections(d); i++ )
         vits->collections[i].target_address = INVALID_PADDR;
 
+    vits->baser0 = GITS_BASER0_INIT_VAL;
+    vits->baser0_save = GITS_BASER0_INIT_VAL;
+
+    /*
+     * Only one virtual ITS is provided to domain.
+     * Assign first physical ITS address to Dom0 virtual ITS.
+     */
+    vits->gits_base = vits_hw.phys_base;
+    vits->gits_size = vits_hw.phys_size;
+
+    register_mmio_handler(d, &vgic_gits_mmio_handler, vits->gits_base,
+                          SZ_64K, NULL);
+
     return 0;
 }
 
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index d59f494..2deed24 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -159,15 +159,6 @@ static void vgic_store_irouter(struct domain *d, struct vgic_irq_rank *rank,
     rank->vcpu[offset] = new_vcpu->vcpu_id;
 }
 
-static inline bool vgic_reg64_check_access(struct hsr_dabt dabt)
-{
-    /*
-     * 64 bits registers can be accessible using 32-bit and 64-bit unless
-     * stated otherwise (See 8.1.3 ARM IHI 0069A).
-     */
-    return ( dabt.size == DABT_DOUBLE_WORD || dabt.size == DABT_WORD );
-}
-
 static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
                                          uint32_t gicr_reg,
                                          register_t *r)
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 0faa2fa..26b2b9e 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -52,6 +52,8 @@
 #define GITS_TYPER_IDBITS(r)		((((r) >> GITS_TYPER_IDBITS_SHIFT) & 0x1f) + 1)
 #define GITS_TYPER_PTA                  (1UL << 19)
 #define GITS_TYPER_HCC_SHIFT            (24)
+#define GITS_TYPER_PHYSICAL_LPIS        (1UL)
+#define GITS_TYPER_ITT_SIZE_SHIFT       (4)
 
 #define GITS_CBASER_VALID               (1UL << 63)
 #define GITS_CBASER_nC                  (1UL << 59)
@@ -64,6 +66,7 @@
 #define GITS_BASER_NR_REGS              8
 
 #define GITS_BASER_VALID                (1UL << 63)
+#define GITS_BASER_INDIRECT_SHIFT       (62)
 #define GITS_BASER_nC                   (1UL << 59)
 #define GITS_BASER_WaWb                 (5UL << 59)
 #define GITS_BASER_TYPE_SHIFT           (56)
@@ -79,6 +82,10 @@
 #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_PAGE_SIZE_4K_VAL     (0)
+#define GITS_BASER_PAGE_SIZE_16K_VAL    (1)
+#define GITS_BASER_PAGE_SIZE_MASK_VAL   (0x3)
+#define GITS_BASER_PAGES_MASK_VAL       (0xff)
 #define GITS_BASER_TYPE_NONE            0
 #define GITS_BASER_TYPE_DEVICE          1
 #define GITS_BASER_TYPE_VCPU            2
@@ -87,6 +94,7 @@
 #define GITS_BASER_TYPE_RESERVED5       5
 #define GITS_BASER_TYPE_RESERVED6       6
 #define GITS_BASER_TYPE_RESERVED7       7
+#define GITS_BASER_PA_MASK              (0xfffffffff000UL)
 
 /*
  * ITS commands
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index f943461..843da8a 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -31,7 +31,14 @@
 #define GICD_IROUTER                 (0x6000)
 #define GICD_IROUTER32               (0x6100)
 #define GICD_IROUTER1019             (0x7FD8)
+#define GICD_PIDR0                   (0xFFE0)
+#define GICD_PIDR1                   (0xFFE4)
 #define GICD_PIDR2                   (0xFFE8)
+#define GICD_PIDR3                   (0xFFEC)
+#define GICD_PIDR4                   (0xFFD0)
+#define GICD_PIDR5                   (0xFFD4)
+#define GICD_PIDR6                   (0xFFD8)
+#define GICD_PIDR7                   (0xFFDC)
 
 /* Common between GICD_PIDR2 and GICR_PIDR2 */
 #define GIC_PIDR2_ARCH_MASK         (0xf0)
@@ -88,7 +95,14 @@
 #define GICR_INVLPIR                 (0x00A0)
 #define GICR_INVALLR                 (0x00B0)
 #define GICR_SYNCR                   (0x00C0)
+#define GICR_PIDR0                   GICD_PIDR0
+#define GICR_PIDR1                   GICD_PIDR1
 #define GICR_PIDR2                   GICD_PIDR2
+#define GICR_PIDR3                   GICD_PIDR3
+#define GICR_PIDR4                   GICD_PIDR4
+#define GICR_PIDR5                   GICD_PIDR5
+#define GICR_PIDR6                   GICD_PIDR6
+#define GICR_PIDR7                   GICD_PIDR7
 
 /* GICR for SGI's & PPI's */
 
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index f3b7df5..f13adfd 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -169,6 +169,15 @@ static inline int REG_RANK_NR(int b, uint32_t n)
 
 #define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
 
+static inline bool vgic_reg64_check_access(struct hsr_dabt dabt)
+{
+    /*
+     * 64 bits registers can be accessible using 32-bit and 64-bit unless
+     * stated otherwise (See 8.1.3 ARM IHI 0069A).
+     */
+    return ( dabt.size == DABT_DOUBLE_WORD || dabt.size == DABT_WORD );
+}
+
 /*
  * The check on the size supported by the register has to be done by
  * the caller of vgic_regN_*.
diff --git a/xen/include/asm-arm/vits.h b/xen/include/asm-arm/vits.h
index 295cce4..5063c18 100644
--- a/xen/include/asm-arm/vits.h
+++ b/xen/include/asm-arm/vits.h
@@ -24,14 +24,37 @@
 struct vgic_its
 {
    spinlock_t lock;
+   /*
+    * Emulation of BASER0. Used by guest to specify
+    * ITS device table memory.
+    */
+   uint64_t baser0;
+   /*
+    * Holds temparary GITS_BASER0 register value. This value
+    * is used to update baser0 after GITS_CTLR.Enabled is set to 1.
+    * This helps to support 32-bit updates on GITS_BASER0.
+    */
+   uint64_t baser0_save;
+   /* GICR ctlr register */
+   uint32_t ctlr;
    /* Command queue base */
-   paddr_t cmd_base;
+   uint64_t cmd_base;
+   /*
+    * Holds temparary GITS_CBASER register value. This value
+    * is used to update cmd_baser after GITS_CTLR.Enabled is set to 1.
+    * This helps to support 32-bit updates on GITS_CBASER.
+    */
+   uint64_t cmd_base_save;
    /* Command queue write pointer */
-   paddr_t cmd_write;
+   uint64_t cmd_write;
    /* Command queue read pointer */
    atomic_t cmd_read;
    /* Command queue size */
    unsigned long cmd_qsize;
+   /* ITS mmio physical base */
+   paddr_t gits_base;
+   /* ITS mmio physical size */
+   unsigned long gits_size;
    /* vITT device table ipa */
    paddr_t dt_ipa;
    /* vITT device table size */
-- 
1.7.9.5

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

* [PATCH v8 18/28] xen/arm: ITS: Export ITS info to Virtual ITS
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (16 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 17/28] xen/arm: ITS: Add GITS registers emulation vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 19/28] xen/arm: ITS: Store the number of LPIs allocated per domain vijayak
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Export physical ITS information to virtual ITS driver

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - eventID_bits and devID_bits are made its node specific.
      Max of all the nodes is considered
    - Moved assert on eventID_bits from its_assign_device()
      to its_add_device()
v7: - Moved gic_its_info from gic-its.h to gic-v3-its.c
    - s/dev_bits/devID_bits
    - s/eventid_bits/eventID_bits
    - Dropped patch #20 and merged changes to this patch
    - Enabled compilation of vITS driver
v6: - Passed only one physical ITS info
    - Passed all the values as parameters
    - Initialize vITS only if physical ITS is available
---
 xen/arch/arm/Makefile      |    1 +
 xen/arch/arm/gic-v3-its.c  |   33 +++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic-v3-its.c |   21 +++++++++++++++++++++
 xen/include/asm-arm/vits.h |    2 ++
 4 files changed, 57 insertions(+)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 4970641..5cc4b37 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -34,6 +34,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 fa88a75..e495d4d 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -37,6 +37,7 @@
 #include <asm/gic.h>
 #include <asm/gic_v3_defs.h>
 #include <asm/gic-its.h>
+#include <asm/vits.h>
 #include <xen/log2.h>
 
 #define its_print(lvl, fmt, ...)                                      \
@@ -86,8 +87,16 @@ struct its_node {
     u64                     flags;
     u32                     ite_size;
     struct dt_device_node   *dt_node;
+    u8                      eventID_bits;
+    u8                      devID_bits;
 };
 
+/* Contains common and collective data of all the its nodes. */
+static struct {
+    u8 eventID_bits;
+    u8 devID_bits;
+} its_data;
+
 #define ITS_ITT_ALIGN    SZ_256
 
 static LIST_HEAD(its_nodes);
@@ -812,6 +821,8 @@ int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its)
         goto err_unlock;
     }
 
+    ASSERT(dev->event_map.nr_lpis < (1 << dev->its->eventID_bits));
+
     BUG_ON(its_insert_device(dev));
     spin_unlock(&rb_its_dev_lock);
 
@@ -915,6 +926,14 @@ int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid)
     return 0;
 }
 
+static void update_its_data(struct its_node *its)
+{
+    if ( its_data.eventID_bits < its->eventID_bits )
+        its_data.eventID_bits = its->eventID_bits;
+    if ( its_data.devID_bits < its->devID_bits )
+        its_data.devID_bits = its->devID_bits;
+}
+
 /*
  * We allocate 64kB for PROPBASE. That gives us at most 64K LPIs to
  * deal with (one configuration byte per interrupt). PENDBASE has to
@@ -1360,6 +1379,9 @@ static int its_probe(struct dt_device_node *node)
     its->phys_size = its_size;
     typer = readl_relaxed(its_base + GITS_TYPER);
     its->ite_size = ((typer >> 4) & 0xf) + 1;
+    its->eventID_bits = GITS_TYPER_IDBITS(typer);
+    its->devID_bits = GITS_TYPER_DEVBITS(typer);
+    update_its_data(its);
 
     its->cmd_base = xzalloc_bytes(ITS_CMD_QUEUE_SZ);
     if ( !its->cmd_base )
@@ -1451,6 +1473,7 @@ int its_cpu_init(void)
 
 int __init its_init(struct rdist_prop *rdists)
 {
+    struct its_node *its;
     struct dt_device_node *np = NULL;
 
     static const struct dt_device_match its_device_ids[] __initconst =
@@ -1473,6 +1496,16 @@ int __init its_init(struct rdist_prop *rdists)
     its_alloc_lpi_tables();
     its_lpi_init(rdists->id_bits);
 
+    its = list_first_entry(&its_nodes, struct its_node, entry);
+    /*
+     * As per vITS design spec, Xen exposes only one virtual ITS per domain.
+     * This simplifies vITS command model. I.e simplifies processing global
+     * ITS commands which does not have device ID on platform having more
+     * than one physical ITS.
+     */
+    vits_setup_hw(its_data.devID_bits, its_data.eventID_bits,
+                  its->phys_base, its->phys_size);
+
     return 0;
 }
 
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index bdcd9f1..36e6385 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -70,6 +70,26 @@ static void dump_cmd(const its_cmd_block *cmd)
 static void dump_cmd(const its_cmd_block *cmd) { }
 #endif
 
+static struct {
+    bool_t enabled;
+    uint8_t devID_bits;
+    uint8_t eventID_bits;
+    /* GITS physical base */
+    paddr_t phys_base;
+    /* GITS physical size */
+    unsigned long phys_size;
+} vits_hw;
+
+void vits_setup_hw(uint8_t devID_bits, uint8_t eventID_bits,
+                   paddr_t phys_base, unsigned long phys_size)
+{
+    vits_hw.enabled = 1;
+    vits_hw.devID_bits = devID_bits;
+    vits_hw.eventID_bits = eventID_bits;
+    vits_hw.phys_base = phys_base;
+    vits_hw.phys_size = phys_size;
+}
+
 static inline uint16_t vits_get_max_collections(struct domain *d)
 {
     /*
@@ -838,6 +858,7 @@ int vits_domain_init(struct domain *d)
     }
 
     ASSERT(is_hardware_domain(d));
+    ASSERT(vits_hw.enabled);
 
     d->arch.vgic.vits = xzalloc(struct vgic_its);
     if ( !d->arch.vgic.vits )
diff --git a/xen/include/asm-arm/vits.h b/xen/include/asm-arm/vits.h
index 5063c18..3579395 100644
--- a/xen/include/asm-arm/vits.h
+++ b/xen/include/asm-arm/vits.h
@@ -93,6 +93,8 @@ int vits_get_vitt_entry(struct domain *d, uint32_t devid, uint32_t event,
                         struct vitt *entry);
 int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
                            struct vdevice_table *entry);
+void vits_setup_hw(uint8_t dev_bits, uint8_t eventid_bits,
+                   paddr_t base, unsigned long size);
 
 #endif /* __ASM_ARM_VITS_H__ */
 /*
-- 
1.7.9.5

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

* [PATCH v8 19/28] xen/arm: ITS: Store the number of LPIs allocated per domain
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (17 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 18/28] xen/arm: ITS: Export ITS info to Virtual ITS vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 20/28] xen/arm: ITS: Add virtual ITS availability check helper vijayak
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Store the number of lpis allocated per domain in vgic structure

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Updated commit message and added comments
    - Removed initialization of vgic.nr_lpis to zero
v7: - Change commit message.
    - Store only nr_lpis per domain in vgic structure and drop
      id_bits.
---
 xen/arch/arm/vgic-v3-its.c   |    6 ++++++
 xen/include/asm-arm/domain.h |    1 +
 2 files changed, 7 insertions(+)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 36e6385..913b49d 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -860,6 +860,12 @@ int vits_domain_init(struct domain *d)
     ASSERT(is_hardware_domain(d));
     ASSERT(vits_hw.enabled);
 
+    /*
+     * HW might support more number of LPIs than specified here for a domain.
+     * Here we limit number of LPIs supported for domain to nr_lpis.
+     */
+    d->arch.vgic.nr_lpis = gic_nr_irq_ids() - FIRST_GIC_LPI;
+
     d->arch.vgic.vits = xzalloc(struct vgic_its);
     if ( !d->arch.vgic.vits )
         return -ENOMEM;
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 0ac62d9..0904204 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -93,6 +93,7 @@ struct arch_domain
         spinlock_t lock;
         uint32_t ctlr;
         int nr_spis; /* Number of SPIs */
+        int nr_lpis; /* Number of LPIs */
         unsigned long *allocated_irqs; /* bitmap of IRQs allocated */
         struct vgic_irq_rank *shared_irqs;
         /*
-- 
1.7.9.5

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

* [PATCH v8 20/28] xen/arm: ITS: Add virtual ITS availability check helper
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (18 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 19/28] xen/arm: ITS: Store the number of LPIs allocated per domain vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 21/28] xen/arm: ITS: Add GICR register emulation vijayak
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Introduce vgic_is_lpi_supported() helper function
to know virtual ITS availability for a domain

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Dropped its_enabled field
v7: - its_enabled field is added to vgic structure
---
 xen/arch/arm/vgic.c        |    5 +++++
 xen/include/asm-arm/vgic.h |    1 +
 2 files changed, 6 insertions(+)

diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index f813931..2d89b7c 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -62,6 +62,11 @@ struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq)
     return vgic_get_rank(v, rank);
 }
 
+bool_t vgic_is_lpi_supported(struct domain *d)
+{
+    return (d->arch.vgic.nr_lpis != 0);
+}
+
 static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
 {
     INIT_LIST_HEAD(&p->inflight);
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index f13adfd..35d06b8 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -311,6 +311,7 @@ extern int vgic_emulate(struct cpu_user_regs *regs, union hsr hsr);
 extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n);
 extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n);
 extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops);
+extern bool_t vgic_is_lpi_supported(struct domain *d);
 int vgic_v2_init(struct domain *d);
 int vgic_v3_init(struct domain *d);
 
-- 
1.7.9.5

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

* [PATCH v8 21/28] xen/arm: ITS: Add GICR register emulation
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (19 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 20/28] xen/arm: ITS: Add virtual ITS availability check helper vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 22/28] xen/arm: ITS: Allocate irq descriptors for LPIs vijayak
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Emulate LPI related changes to GICR registers

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Updated GICR_PROPBASER and GICR_PENDBASER only on enabling
      LPIs and added 32/64 bit reg access
    - Allocated LPI property table of size supported by Xen.
    - Moved LPI property table related variables to vgic from vits
      structure.
    - Used Tasklet to parse LPI property table and update pending irq
      structures
    - Check is made in INV command processing to wait for LPI
      property table update before returning.
v7: - Merged patch#23 to this patch. patch#23 is just one line.
    - Add 32-bit access to GICR_TYPER register
    - Changed dprintk to printk
    - LPI property table is handling is changed. Call {enable,disable}_lpi
      only for nr_lpis.
    - Changes to GICD_TYPER emulation.
v6: - Moved LPI handling code to vgic-v3.c
    - parse LPI property table on GICR_PROPBASER update
    - use vgic_is_lpi_supported()
v5: - Handled all sizes access to LPI configuration table
    - Rename vits_unmap_lpi_prop as  vits_map_lpi_prop
v4: - Added LPI configuration table emulation
    - Rename function inline with vits
    - Copied guest lpi configuration table to xen
---
 xen/arch/arm/vgic-v3-its.c        |   18 ++
 xen/arch/arm/vgic-v3.c            |  419 +++++++++++++++++++++++++++++++++++--
 xen/arch/arm/vgic.c               |   24 ++-
 xen/include/asm-arm/domain.h      |   31 +++
 xen/include/asm-arm/gic-its.h     |    1 +
 xen/include/asm-arm/gic_v3_defs.h |    3 +
 xen/include/asm-arm/vgic.h        |    3 +
 7 files changed, 479 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 913b49d..1bb7674 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -23,12 +23,14 @@
 #include <xen/sched.h>
 #include <xen/sizes.h>
 #include <xen/domain_page.h>
+#include <xen/delay.h>
 #include <asm/device.h>
 #include <asm/mmio.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
 #include <asm/gic_v3_defs.h>
 #include <asm/gic.h>
+#include <asm/gic-its.h>
 #include <asm/vgic.h>
 #include <asm/gic-its.h>
 #include <asm/vits.h>
@@ -299,6 +301,22 @@ static int vits_process_discard(struct vcpu *v, struct vgic_its *vits,
 static int vits_process_inv(struct vcpu *v, struct vgic_its *vits,
                             its_cmd_block *virt_cmd)
 {
+    unsigned long flags;
+    int state;
+
+    /* Do no complete INV command until lpi property table
+     * is under update by tasklet
+     */
+    do {
+        spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags);
+        state = v->domain->arch.vgic.lpi_prop_table_state;
+        spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+        if ( state != LPI_TAB_IN_PROGRESS )
+            break;
+        cpu_relax();
+        udelay(1);
+    } while ( 1 );
+
     /* Ignored */
     DPRINTK("%pv vITS: INV: dev_id 0x%"PRIx32" id %"PRIu32"\n",
             v, virt_cmd->inv.devid, virt_cmd->inv.event);
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 2deed24..aa3c5ed 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -26,10 +26,14 @@
 #include <xen/irq.h>
 #include <xen/sched.h>
 #include <xen/sizes.h>
+#include <xen/tasklet.h>
 #include <asm/current.h>
 #include <asm/mmio.h>
 #include <asm/gic_v3_defs.h>
+#include <asm/gic.h>
+#include <asm/gic-its.h>
 #include <asm/vgic.h>
+#include <asm/vits.h>
 #include <asm/vgic-emul.h>
 
 /*
@@ -159,6 +163,252 @@ static void vgic_store_irouter(struct domain *d, struct vgic_irq_rank *rank,
     rank->vcpu[offset] = new_vcpu->vcpu_id;
 }
 
+static void vgic_v3_disable_lpi(struct vcpu *v, uint32_t vlpi)
+{
+    struct pending_irq *p;
+    struct vcpu *v_target = v->domain->vcpu[0];
+
+    p = irq_to_pending(v_target, vlpi);
+    if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) )
+    {
+        clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+        gic_remove_from_queues(v_target, vlpi);
+    }
+}
+
+static void vgic_v3_enable_lpi(struct vcpu *v, uint32_t vlpi)
+{
+    struct pending_irq *p;
+    unsigned long flags;
+    struct vcpu *v_target = vgic_get_target_vcpu(v, vlpi);
+
+    p = irq_to_pending(v_target, vlpi);
+
+    set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+
+    spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
+
+    if ( !list_empty(&p->inflight) &&
+         !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
+        gic_raise_guest_irq(v_target, vlpi, p->priority);
+
+    spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
+}
+
+static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info,
+                                      register_t *r, void *priv)
+{
+    uint32_t offset;
+    void *addr;
+    unsigned long flags;
+    struct hsr_dabt dabt = info->dabt;
+
+    spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags);
+
+    offset = info->gpa -
+                 (v->domain->arch.vgic.propbase & GICR_PROPBASER_PA_MASK);
+    addr = (void *)((u8 *)v->domain->arch.vgic.prop_page + offset);
+
+    switch (dabt.size)
+    {
+    case DABT_DOUBLE_WORD:
+        *r = *((u64 *)addr);
+        break;
+    case DABT_WORD:
+        *r = *((u32 *)addr);
+        break;
+    case DABT_HALF_WORD:
+        *r = *((u16 *)addr);
+        break;
+    default:
+        *r = *((u8 *)addr);
+    }
+    spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+
+    return 1;
+}
+
+static void vgic_v3_gits_update_lpis_state(struct vcpu *v, uint32_t vid,
+                                           uint32_t size)
+{
+    uint32_t i;
+    uint8_t cfg, *p;
+    bool_t enable;
+
+    ASSERT(spin_is_locked(&v->domain->arch.vgic.prop_lock));
+
+    p = ((u8 *)v->domain->arch.vgic.prop_page + vid);
+
+    for ( i = 0 ; i < size; i++ )
+    {
+        cfg = *p;
+        enable = cfg & LPI_PROP_ENABLED;
+
+        /* LPIs start from 8192, So add 8192 to point to correct LPI number */
+        if ( !enable )
+            vgic_v3_enable_lpi(v, vid + FIRST_GIC_LPI);
+        else
+            vgic_v3_disable_lpi(v, vid + FIRST_GIC_LPI);
+
+        p++;
+        vid++;
+    }
+}
+
+static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info,
+                                       register_t r, void *priv)
+{
+    uint32_t offset;
+    uint8_t *p, *val, i, iter;
+    bool_t enable;
+    unsigned long flags;
+    struct hsr_dabt dabt = info->dabt;
+
+    spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags);
+
+    offset = info->gpa -
+                 (v->domain->arch.vgic.propbase & GICR_PROPBASER_PA_MASK);
+
+    p = ((u8 *)v->domain->arch.vgic.prop_page + offset);
+    val = (u8 *)&r;
+    iter = 1 << dabt.size;
+
+    for ( i = 0 ; i < iter; i++ )
+    {
+        enable = (*p & *val) & LPI_PROP_ENABLED;
+
+        if ( !enable )
+            vgic_v3_enable_lpi(v, offset + FIRST_GIC_LPI);
+        else
+            vgic_v3_disable_lpi(v, offset + FIRST_GIC_LPI);
+
+        /* Update virtual prop page */
+        val++;
+        p++;
+        offset++;
+    }
+
+    spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+
+    return 1;
+}
+
+static const struct mmio_handler_ops vgic_gits_lpi_mmio_handler = {
+    .read  = vgic_v3_gits_lpi_mmio_read,
+    .write = vgic_v3_gits_lpi_mmio_write,
+};
+
+static void lpi_prop_table_tasklet_func(unsigned long data)
+{
+    unsigned long flags;
+    uint32_t i, id_bits, lpi_size;
+    struct domain *d = (struct domain *)data;
+    struct vcpu *v = d->vcpu[0];
+
+    spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags);
+
+    id_bits = ((v->domain->arch.vgic.propbase & GICR_PROPBASER_IDBITS_MASK) +
+               1);
+    lpi_size = min_t(unsigned int, v->domain->arch.vgic.prop_size, 1 << id_bits);
+
+    for ( i = 0; i < lpi_size / PAGE_SIZE; i++ )
+    {
+        if ( ((i * PAGE_SIZE) + PAGE_SIZE) < v->domain->arch.vgic.nr_lpis )
+            vgic_v3_gits_update_lpis_state(v, (i * PAGE_SIZE), PAGE_SIZE);
+    }
+
+    v->domain->arch.vgic.lpi_prop_table_state = LPI_TAB_UPDATED;
+    spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+}
+
+static int vgic_v3_map_lpi_prop(struct vcpu *v)
+{
+    paddr_t gaddr, addr;
+    unsigned long mfn, flags;
+    uint32_t id_bits, vgic_id_bits, lpi_size;
+    int i;
+
+    gaddr = v->domain->arch.vgic.propbase & GICR_PROPBASER_PA_MASK;
+    id_bits = ((v->domain->arch.vgic.propbase & GICR_PROPBASER_IDBITS_MASK) +
+               1);
+
+    vgic_id_bits = get_count_order(v->domain->arch.vgic.nr_lpis +
+                                   FIRST_GIC_LPI);
+
+    spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags);
+
+    /*
+     * Here we limit the size of LPI property table to the number of LPIs
+     * that domain supports.
+     */
+    lpi_size = 1 << vgic_id_bits;
+
+    /*
+     * Allocate Virtual LPI Property table.
+     * TODO: To re-use guest property table
+     * TODO: Free prog_page table that is already allocated.
+     */
+    v->domain->arch.vgic.prop_page =
+        alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0);
+    if ( !v->domain->arch.vgic.prop_page )
+    {
+        spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+        printk(XENLOG_G_ERR
+               "d%d: vITS: Fail to allocate LPI Prop page\n",
+               v->domain->domain_id);
+        return 0;
+    }
+
+    v->domain->arch.vgic.prop_size  = lpi_size;
+
+    /*
+     * lpi_size is always aligned to PAGE_SIZE because it is generated from
+     * vgic_id_bits which is computed using get_count_order.
+     *
+     * Consider minimum size of Xen supported size(vgic.nr_lpis) or
+     * guest allocated size LPI property table.
+     */
+    lpi_size = min_t(unsigned int, v->domain->arch.vgic.prop_size, 1 << id_bits);
+
+    addr = gaddr;
+    for ( i = 0; i < lpi_size / PAGE_SIZE; i++ )
+    {
+        vgic_access_guest_memory(v->domain, addr,
+                                 (void *)(v->domain->arch.vgic.prop_page +
+                                 (i * PAGE_SIZE)), PAGE_SIZE, 0);
+
+        /* Unmap LPI property table. */
+        mfn = gmfn_to_mfn(v->domain, paddr_to_pfn(addr));
+        if ( unlikely(!mfn_valid(mfn)) )
+        {
+            spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+            printk(XENLOG_G_ERR
+                   "vITS: Invalid propbaser address %"PRIx64" for domain %d\n",
+                   addr, v->domain->domain_id);
+            return 0;
+        }
+        guest_physmap_remove_page(v->domain, paddr_to_pfn(addr), mfn, 0);
+        addr += PAGE_SIZE;
+    }
+
+    /*
+     * Each re-distributor shares a common LPI configuration table
+     * So one set of mmio handlers to manage configuration table is enough
+     *
+     * Register mmio handlers for this region.
+     */
+    register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler,
+                          gaddr, v->domain->arch.vgic.prop_size, NULL);
+
+    v->domain->arch.vgic.lpi_prop_table_state = LPI_TAB_IN_PROGRESS;
+    spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+
+    /* Schedule tasklet */
+    tasklet_schedule(&v->domain->arch.vgic.lpi_prop_table_tasklet);
+
+    return 1;
+}
+
 static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
                                          uint32_t gicr_reg,
                                          register_t *r)
@@ -168,9 +418,11 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
     switch ( gicr_reg )
     {
     case VREG32(GICR_CTLR):
-        /* We have not implemented LPI's, read zero */
-        goto read_as_zero_32;
-
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        vgic_lock(v);
+        *r = vgic_reg32_extract(v->arch.vgic.gicr_ctlr, info);
+        vgic_unlock(v);
+        return 1;
     case VREG32(GICR_IIDR):
         if ( dabt.size != DABT_WORD ) goto bad_width;
         *r = vgic_reg32_extract(GICV3_GICR_IIDR_VAL, info);
@@ -191,6 +443,12 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
         if ( v->arch.vgic.flags & VGIC_V3_RDIST_LAST )
             typer |= GICR_TYPER_LAST;
 
+        /* Set Physical LPIs support */
+        if ( vgic_is_lpi_supported(v->domain) )
+            typer |= GICR_TYPER_PLPIS;
+        /* Provide vcpu number as target address */
+        typer |= (v->vcpu_id << GICR_TYPER_PROCESSOR_SHIFT);
+
         *r = vgic_reg64_extract(typer, info);
 
         return 1;
@@ -222,12 +480,40 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
         goto read_reserved;
 
     case VREG64(GICR_PROPBASER):
-        /* LPI's not implemented */
-        goto read_as_zero_64;
+    {
+        uint32_t val;
+
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        if ( !vgic_is_lpi_supported(v->domain) )
+            goto read_as_zero_64;
+
+        vgic_lock(v);
+        val = v->arch.vgic.gicr_ctlr;
+        vgic_unlock(v);
+
+        vgic_lpi_prop_lock(v);
+        if ( val & GICR_CTLR_ENABLE_LPIS )
+            *r = vgic_reg64_extract(v->domain->arch.vgic.propbase, info);
+        else
+            *r = vgic_reg64_extract(v->domain->arch.vgic.propbase_save, info);
+        vgic_lpi_prop_unlock(v);
+        return 1;
+    }
 
     case VREG64(GICR_PENDBASER):
-        /* LPI's not implemented */
-        goto read_as_zero_64;
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        if ( !vgic_is_lpi_supported(v->domain) )
+            goto read_as_zero_64;
+        vgic_lock(v);
+        /* PTZ field is RAZ */
+        if ( v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS )
+            *r = vgic_reg64_extract(v->arch.vgic.pendbase &
+                                    ~GICR_PENDBASER_PTZ_MASK, info);
+        else
+            *r = vgic_reg64_extract(v->arch.vgic.pendbase_save &
+                                    ~GICR_PENDBASER_PTZ_MASK, info);
+        vgic_unlock(v);
+        return 1;
 
     case 0x0080:
         goto read_reserved;
@@ -329,13 +615,54 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
                                           register_t r)
 {
     struct hsr_dabt dabt = info->dabt;
+    uint32_t val;
 
     switch ( gicr_reg )
     {
     case VREG32(GICR_CTLR):
-        /* LPI's not implemented */
+        if ( dabt.size != DABT_WORD ) goto bad_width;
+        if ( !vgic_is_lpi_supported(v->domain) )
         goto write_ignore_32;
+        /*
+         * Enable LPI's for ITS. Direct injection of LPI
+         * by writing to GICR_{SET,CLR}LPIR is not supported.
+         */
+        vgic_lock(v);
+        val = v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS;
+        vgic_reg32_update(&v->arch.vgic.gicr_ctlr,
+                         (r & GICR_CTLR_ENABLE_LPIS), info);
+
+        /* If no change in GICR_CTRL.EnableLPIs. Just return */ 
+        if ( !((val ^ v->arch.vgic.gicr_ctlr) &&
+             (v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) )
+        {
+            vgic_unlock(v);
+            return 1;
+        }
+        vgic_unlock(v);
 
+        vgic_lpi_prop_lock(v);
+        /*
+         * On GICR_CTLR.EnableLPIs = 1, update pendbaser and propbase
+         * with pendbase_save and propbase_save if they are changed.
+         */
+        if ( v->arch.vgic.pendbase_save ^ v->arch.vgic.pendbase )
+             v->arch.vgic.pendbase = v->arch.vgic.pendbase_save;
+        if ( v->domain->arch.vgic.propbase_save ^ v->domain->arch.vgic.propbase )
+        {
+            if ( v->vcpu_id == 0 )
+            {
+                v->domain->arch.vgic.propbase =
+                    v->domain->arch.vgic.propbase_save;
+                vgic_lpi_prop_unlock(v);
+                return vgic_v3_map_lpi_prop(v);
+            }
+            else
+                v->domain->arch.vgic.propbase =
+                    v->domain->arch.vgic.propbase_save;
+        }
+        vgic_lpi_prop_unlock(v);
+        return 1;
     case VREG32(GICR_IIDR):
         /* RO */
         goto write_ignore_32;
@@ -370,12 +697,51 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
         goto write_reserved;
 
     case VREG64(GICR_PROPBASER):
-        /* LPI is not implemented */
-        goto write_ignore_64;
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        if ( !vgic_is_lpi_supported(v->domain) )
+            goto write_ignore_64;
+        /*
+         * As per spec, updating GICR_PROPBASER when GICR_CTLR.EnableLPIs = 1
+         * is unpredictable. Here we ignore the update.
+         */
+        vgic_lock(v);
+        val = v->arch.vgic.gicr_ctlr;
+        vgic_unlock(v);
+
+        if ( val & GICR_CTLR_ENABLE_LPIS )
+            goto write_ignore_64;
+        vgic_lpi_prop_lock(v);
+        /*
+         * LPI configuration tables are shared across cpus. Should be same.
+         *
+         * Allow updating on propbase only for vcpu0 once with below check.
+         * TODO: Manage change in property table.
+         */
+        if ( v->vcpu_id == 0 && v->domain->arch.vgic.propbase_save != 0 )
+        {
+            printk(XENLOG_G_WARNING
+                   "%pv: vGICR: Updating LPI propbase is not allowed\n", v);
+            vgic_lpi_prop_unlock(v);
+            return 1;
+        }
+        vgic_reg64_update(&v->domain->arch.vgic.propbase_save, r, info);
+        vgic_lpi_prop_unlock(v);
+        return 1;
 
     case VREG64(GICR_PENDBASER):
-        /* LPI is not implemented */
-        goto write_ignore_64;
+        if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
+        if ( !vgic_is_lpi_supported(v->domain) )
+            goto write_ignore_64;
+        /* Just hold pendbaser value for guest read */
+        vgic_lock(v);
+        if ( v->arch.vgic.gicr_ctlr & GICR_CTLR_ENABLE_LPIS )
+        {
+            vgic_unlock(v);
+            goto write_ignore_64;
+        }
+        vgic_reg64_update(&v->arch.vgic.pendbase_save, r, info);
+        vgic_unlock(v);
+        return 1;
 
     case 0x0080:
         goto write_reserved;
@@ -441,7 +807,7 @@ bad_width:
     return 0;
 
 write_ignore_64:
-    if ( vgic_reg64_check_access(dabt) ) goto bad_width;
+    if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
     return 1;
 
 write_ignore_32:
@@ -899,11 +1265,7 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
 
     case VREG32(GICD_TYPER):
     {
-        /*
-         * Number of interrupt identifier bits supported by the GIC
-         * Stream Protocol Interface
-         */
-        unsigned int irq_bits = get_count_order(vgic_num_irq_lines(v->domain));
+        unsigned int irqs;
         /*
          * Number of processors that may be used as interrupt targets when ARE
          * bit is zero. The maximum is 8.
@@ -916,7 +1278,15 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info,
         typer = ((ncpus - 1) << GICD_TYPER_CPUS_SHIFT |
                  DIV_ROUND_UP(v->domain->arch.vgic.nr_spis, 32));
 
-        typer |= (irq_bits - 1) << GICD_TYPER_ID_BITS_SHIFT;
+        if ( vgic_is_lpi_supported(v->domain) )
+        {
+            irqs = v->domain->arch.vgic.nr_lpis + FIRST_GIC_LPI;
+            typer |= GICD_TYPER_LPIS_SUPPORTED;
+        }
+        else
+            irqs = vgic_num_irq_lines(v->domain);
+
+        typer |= (get_count_order(irqs) - 1) << GICD_TYPER_ID_BITS_SHIFT;
 
         *r = vgic_reg32_extract(typer, info);
 
@@ -1459,6 +1829,17 @@ static int vgic_v3_domain_init(struct domain *d)
 
     d->arch.vgic.ctlr = VGICD_CTLR_DEFAULT;
 
+    spin_lock_init(&d->arch.vgic.prop_lock);
+
+    if ( is_hardware_domain(d) && vgic_v3_hw.its_support )
+    {
+        if ( vits_domain_init(d) )
+            return -ENODEV;
+
+        tasklet_init(&d->arch.vgic.lpi_prop_table_tasklet,
+                     lpi_prop_table_tasklet_func, (unsigned long)d);
+    }
+
     return 0;
 }
 
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 2d89b7c..8d75d90 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -67,6 +67,12 @@ bool_t vgic_is_lpi_supported(struct domain *d)
     return (d->arch.vgic.nr_lpis != 0);
 }
 
+static bool_t vgic_is_domain_lpi(struct domain *d, unsigned int lpi)
+{
+    return ((lpi >= FIRST_GIC_LPI) &&
+            (lpi < (d->arch.vgic.nr_lpis + FIRST_GIC_LPI)));
+}
+
 static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
 {
     INIT_LIST_HEAD(&p->inflight);
@@ -186,6 +192,10 @@ void domain_vgic_free(struct domain *d)
     xfree(d->arch.vgic.shared_irqs);
     xfree(d->arch.vgic.pending_irqs);
     xfree(d->arch.vgic.allocated_irqs);
+
+    if ( vgic_is_lpi_supported(d) && d->arch.vgic.prop_page != NULL )
+        free_xenheap_pages(d->arch.vgic.prop_page,
+                           get_order_from_bytes(d->arch.vgic.prop_size));
 }
 
 int vcpu_vgic_init(struct vcpu *v)
@@ -232,9 +242,21 @@ static struct vcpu *__vgic_get_target_vcpu(struct vcpu *v, unsigned int virq)
 struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq)
 {
     struct vcpu *v_target;
-    struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
+    struct vgic_irq_rank *rank;
     unsigned long flags;
 
+    /*
+     * We don't have vlpi to plpi mapping and hence we cannot
+     * have target on which corresponding vlpi is enabled.
+     * So for now we are always injecting vlpi on vcpu0.
+     * (See vgic_vcpu_inject_lpi() function) and so we get pending_irq
+     * structure on vcpu0.
+     * TODO: Get correct target vcpu
+     */
+    if ( vgic_is_domain_lpi(v->domain, virq) )
+        return v->domain->vcpu[0];
+
+    rank = vgic_rank_irq(v, virq);
     vgic_lock_rank(v, rank, flags);
     v_target = __vgic_get_target_vcpu(v, virq);
     vgic_unlock_rank(v, rank, flags);
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 0904204..48dcd9a 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -12,6 +12,7 @@
 #include <public/hvm/params.h>
 #include <xen/serial.h>
 #include <xen/hvm/iommu.h>
+#include <xen/tasklet.h>
 
 struct hvm_domain
 {
@@ -116,6 +117,26 @@ struct arch_domain
         /* Virtual ITS */
         struct vgic_its *vits;
 #endif
+        /* LPI propbase */
+        uint64_t propbase;
+        /*
+         * Holds temparary GICR_PROPBASER register value. This value
+         * is used to update propbase after GICR_CTLR.EnableLPIs is set to 1.
+         * This helps to support 32-bit updates on GICR_PROPBASER
+         */
+        uint64_t propbase_save;
+        /* Virtual LPI property table */
+        void *prop_page;
+        /* Virtual LPI property size */
+        uint32_t prop_size;
+        /* spinlock to protect lpi property table */
+        spinlock_t prop_lock;
+#define LPI_TAB_IN_PROGRESS    1
+#define LPI_TAB_UPDATED        2
+        /* lpi property table state */
+        int lpi_prop_table_state;
+        /* Tasklet for parsing lpi property table */
+        struct tasklet lpi_prop_table_tasklet;
     } vgic;
 
     struct vuart {
@@ -248,6 +269,16 @@ struct arch_vcpu
 
         /* GICv3: redistributor base and flags for this vCPU */
         paddr_t rdist_base;
+        /* GICv3-ITS: LPI pending table for this vCPU */
+        uint64_t pendbase;
+        /*
+         * Holds temparary GICR_PENDBASER register value. This value
+         * is used to update propbase after GICR_CTLR.EnableLPIs is set to 1.
+         * This helps to support 32-bit updates on GICR_PENDBASER.
+         */
+        uint64_t pendbase_save;
+        /* GICv3: Redistributor control register */
+        uint32_t gicr_ctlr;
 #define VGIC_V3_RDIST_LAST  (1 << 0)        /* last vCPU of the rdist */
         uint8_t flags;
     } vgic;
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 26b2b9e..aad51fa 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -114,6 +114,7 @@
 
 #define LPI_PROP_ENABLED                (1 << 0)
 #define LPI_PROP_GROUP1                 (1 << 1)
+#define LPI_PRIORITY_MASK               (0xfc)
 
 /*
  * Collection structure - just an ID, and a redistributor address to
diff --git a/xen/include/asm-arm/gic_v3_defs.h b/xen/include/asm-arm/gic_v3_defs.h
index 843da8a..bf3c53d 100644
--- a/xen/include/asm-arm/gic_v3_defs.h
+++ b/xen/include/asm-arm/gic_v3_defs.h
@@ -129,14 +129,17 @@
 #define GICR_PROPBASER_WaWb              (5U << 7)
 #define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7)
 #define GICR_PROPBASER_IDBITS_MASK       (0x1f)
+#define GICR_PROPBASER_PA_MASK           (0xfffffffff000UL)
 #define GICR_TYPER_PLPIS             (1U << 0)
 #define GICR_TYPER_VLPIS             (1U << 1)
 #define GICR_TYPER_LAST              (1U << 4)
+#define GICR_TYPER_PROCESSOR_SHIFT   (8)
 
 #define GICR_PENDBASER_InnerShareable    (1U << 10)
 #define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10)
 #define GICR_PENDBASER_nC                (1U << 7)
 #define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7)
+#define GICR_PENDBASER_PTZ_MASK          (1UL << 62)
 
 #define DEFAULT_PMR_VALUE            0xff
 
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 35d06b8..473fd8e 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -143,6 +143,9 @@ struct vgic_ops {
 #define vgic_lock_rank(v, r, flags)   spin_lock_irqsave(&(r)->lock, flags)
 #define vgic_unlock_rank(v, r, flags) spin_unlock_irqrestore(&(r)->lock, flags)
 
+#define vgic_lpi_prop_lock(v)   spin_lock_irq(&(v)->domain->arch.vgic.prop_lock)
+#define vgic_lpi_prop_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.prop_lock)
+
 /*
  * Rank containing GICD_<FOO><n> for GICD_<FOO> with
  * <b>-bits-per-interrupt
-- 
1.7.9.5

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

* [PATCH v8 22/28] xen/arm: ITS: Allocate irq descriptors for LPIs
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (20 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 21/28] xen/arm: ITS: Add GICR register emulation vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 23/28] xen/arm: ITS: Allocate pending_lpi " vijayak
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Allocate dynamically irq descriptors for LPIs

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Use gic_nr_irq_ids() instead of nr_lpis
v6: - Add separate patch for irq_pending structures
    - renamed and moved is_domain_lpi to vgic
    - Updated __irq_to_domain
---
 xen/arch/arm/gic-v3-its.c |    4 ++++
 xen/arch/arm/irq.c        |   37 ++++++++++++++++++++++++++++++++++++-
 xen/include/asm-arm/irq.h |    1 +
 3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index e495d4d..1dcfc39 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -1496,6 +1496,10 @@ int __init its_init(struct rdist_prop *rdists)
     its_alloc_lpi_tables();
     its_lpi_init(rdists->id_bits);
 
+    /* Allocate irq descriptors for LPIs */
+    if ( init_lpi() )
+        return -ENOMEM;
+
     its = list_first_entry(&its_nodes, struct its_node, entry);
     /*
      * As per vITS design spec, Xen exposes only one virtual ITS per domain.
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 3baac5d..e4c6019 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -31,6 +31,8 @@
 static unsigned int local_irqs_type[NR_LOCAL_IRQS];
 static DEFINE_SPINLOCK(local_irqs_type_lock);
 
+static irq_desc_t *irq_desc_lpi;
+
 /* Describe an IRQ assigned to a guest */
 struct irq_guest
 {
@@ -61,7 +63,15 @@ static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
 irq_desc_t *__irq_to_desc(int irq)
 {
     if (irq < NR_LOCAL_IRQS) return &this_cpu(local_irq_desc)[irq];
-    return &irq_desc[irq-NR_LOCAL_IRQS];
+    else if ( gic_is_lpi(irq) )
+    {
+        ASSERT(irq_desc_lpi != NULL);
+        return &irq_desc_lpi[irq - FIRST_GIC_LPI];
+    }
+    else
+        return &irq_desc[irq - NR_LOCAL_IRQS];
+
+    return NULL;
 }
 
 int __init arch_init_one_irq_desc(struct irq_desc *desc)
@@ -111,6 +121,31 @@ static int init_local_irq_data(void)
     return 0;
 }
 
+int init_lpi(void)
+{
+    struct irq_desc *desc;
+    unsigned int i, nr_lpis;
+
+    nr_lpis = gic_nr_irq_ids() - FIRST_GIC_LPI;
+    ASSERT(nr_lpis >= 0);
+
+    /* Allocate LPI irq descriptors */
+    irq_desc_lpi = xzalloc_array(struct irq_desc, nr_lpis);
+    if ( !irq_desc_lpi )
+        return -ENOMEM;
+
+    for ( i = 0; i < nr_lpis; i++ )
+    {
+       desc = &irq_desc_lpi[i];
+       init_one_irq_desc(desc);
+       desc->irq = FIRST_GIC_LPI + i;
+       desc->arch.type = DT_IRQ_TYPE_EDGE_BOTH;
+       desc->action = NULL;
+    }
+
+    return 0;
+}
+
 void __init init_IRQ(void)
 {
     int irq;
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 4bb9464..323f6c0 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -65,6 +65,7 @@ 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);
 void irq_set_msi_desc(struct irq_desc *desc, struct msi_desc *msi);
 struct msi_desc *irq_get_msi_desc(struct irq_desc *desc);
+int init_lpi(void);
 
 #endif /* _ASM_HW_IRQ_H */
 /*
-- 
1.7.9.5

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

* [PATCH v8 23/28] xen/arm: ITS: Allocate pending_lpi descriptors for LPIs
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (21 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 22/28] xen/arm: ITS: Allocate irq descriptors for LPIs vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 24/28] xen/arm: ITS: Route LPIs vijayak
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Allocate dynamically pending_lpi descriptors for LPIs

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v8: - Dropped HAS_GICV3 config switch around pending_lpis[]
---
 xen/arch/arm/vgic-v3-its.c   |    9 +++++++++
 xen/arch/arm/vgic.c          |   12 +++++++++---
 xen/include/asm-arm/domain.h |    1 +
 xen/include/asm-arm/vgic.h   |    1 +
 4 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 1bb7674..41e0b2a 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -890,6 +890,14 @@ int vits_domain_init(struct domain *d)
 
     vits = d->arch.vgic.vits;
 
+    d->arch.vgic.pending_lpis = xzalloc_array(struct pending_irq,
+                                              d->arch.vgic.nr_lpis);
+    if ( d->arch.vgic.pending_lpis == NULL )
+        return -ENOMEM;
+
+    for ( i = 0; i < d->arch.vgic.nr_lpis; i++ )
+        vgic_init_pending_irq(&d->arch.vgic.pending_lpis[i], i + FIRST_GIC_LPI);
+
     spin_lock_init(&vits->lock);
 
     vits->collections = xzalloc_array(struct its_collection,
@@ -918,6 +926,7 @@ int vits_domain_init(struct domain *d)
 
 void vits_domain_free(struct domain *d)
 {
+   xfree(d->arch.vgic.pending_lpis);
    xfree(d->arch.vgic.vits->collections);
    xfree(d->arch.vgic.vits);
 }
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 8d75d90..5b81583 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -73,7 +73,7 @@ static bool_t vgic_is_domain_lpi(struct domain *d, unsigned int lpi)
             (lpi < (d->arch.vgic.nr_lpis + FIRST_GIC_LPI)));
 }
 
-static void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
+void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq)
 {
     INIT_LIST_HEAD(&p->inflight);
     INIT_LIST_HEAD(&p->lr_queue);
@@ -446,13 +446,19 @@ 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 */
+     * are used for SPIs; the rests are used for per cpu irqs.
+     * For LPIs pending_irq structures are allocated separately */
     if ( irq < 32 )
         n = &v->arch.vgic.pending_irqs[irq];
+    else if ( vgic_is_domain_lpi(v->domain, irq) )
+        n = &v->domain->arch.vgic.pending_lpis[irq - FIRST_GIC_LPI];
     else
         n = &v->domain->arch.vgic.pending_irqs[irq - 32];
+
+    ASSERT(n != NULL);
+
     return n;
 }
 
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 48dcd9a..42182a6 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -102,6 +102,7 @@ struct arch_domain
          * struct arch_vcpu.
          */
         struct pending_irq *pending_irqs;
+        struct pending_irq *pending_lpis;
         /* Base address for guest GIC */
         paddr_t dbase; /* Distributor base address */
 #ifdef CONFIG_HAS_GICV3
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 473fd8e..4711d3a 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -323,6 +323,7 @@ extern int vgic_to_sgi(struct vcpu *v, register_t sgir,
                        enum gic_sgi_mode irqmode, int virq,
                        const struct sgi_target *target);
 extern void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq);
+extern void vgic_init_pending_irq(struct pending_irq *p, unsigned int virq);
 
 /* Reserve a specific guest vIRQ */
 extern bool_t vgic_reserve_virq(struct domain *d, unsigned int virq);
-- 
1.7.9.5

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

* [PATCH v8 24/28] xen/arm: ITS: Route LPIs
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (22 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 23/28] xen/arm: ITS: Allocate pending_lpi " vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 25/28] xen/arm: ITS: Add domain specific ITS initialization vijayak
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Allocate and initialize irq descriptor for LPIs and
route LPIs to guest

For LPIs deactivation is not required. Hence
GICH_LR.HW is not required to set.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v7: - Subtract 8192 from irq number to index to lpi property
      table to read priority
v6: - Moved ITS specific code from irq.c to vgic.c and
      introduced vgic_vcpu_raise_lpi()
    - Renamed gicv3_set_properties to gicv3_set_irq_properties
    - Always Inject LPI to vcpu0
    - Changed route_lpi_to_guest definition
---
 xen/arch/arm/gic-v3-its.c     |   17 ++++++-
 xen/arch/arm/gic-v3.c         |   16 ++++--
 xen/arch/arm/gic.c            |   32 +++++++++++-
 xen/arch/arm/irq.c            |  112 ++++++++++++++++++++++++++++++++++++++---
 xen/arch/arm/vgic-v3-its.c    |    2 +-
 xen/arch/arm/vgic.c           |  103 +++++++++++++++++++++++++++++++++++--
 xen/include/asm-arm/gic-its.h |    3 ++
 xen/include/asm-arm/gic.h     |    8 ++-
 xen/include/asm-arm/irq.h     |    2 +
 xen/include/asm-arm/vgic.h    |    3 ++
 10 files changed, 276 insertions(+), 22 deletions(-)

diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index 1dcfc39..cbf517a 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -475,6 +475,21 @@ static void its_flush_and_invalidate_prop(struct irq_desc *desc, const u8 *cfg)
     its_send_inv(its_dev, vid);
 }
 
+void its_set_lpi_properties(struct irq_desc *desc,
+                            const cpumask_t *cpu_mask,
+                            unsigned int priority)
+{
+    unsigned long flags;
+    u8 *cfg;
+
+    spin_lock_irqsave(&its_lock, flags);
+    cfg = gic_rdists->prop_page + desc->irq - FIRST_GIC_LPI;
+    *cfg = (*cfg & 3) | (priority & LPI_PRIORITY_MASK) ;
+
+    its_flush_and_invalidate_prop(desc, cfg);
+    spin_unlock_irqrestore(&its_lock, flags);
+}
+
 static void its_set_lpi_state(struct irq_desc *desc, int enable)
 {
     u8 *cfg;
@@ -920,7 +935,7 @@ int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid)
     for ( i = 0; i < pdev->event_map.nr_lpis; i++ )
     {
         plpi = its_get_plpi(pdev, i);
-        /* TODO: Route lpi */
+        route_lpi_to_guest(d, plpi, "LPI");
     }
 
     return 0;
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 73b2708..47e6b8a 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -498,9 +498,9 @@ static inline uint64_t gicv3_mpidr_to_affinity(int cpu)
              MPIDR_AFFINITY_LEVEL(mpidr, 0));
 }
 
-static void gicv3_set_irq_properties(struct irq_desc *desc,
-                                     const cpumask_t *cpu_mask,
-                                     unsigned int priority)
+static void gicv3_set_line_properties(struct irq_desc *desc,
+                                      const cpumask_t *cpu_mask,
+                                      unsigned int priority)
 {
     uint32_t cfg, actual, edgebit;
     uint64_t affinity;
@@ -564,6 +564,16 @@ static int gicv3_dist_supports_lpis(void)
     return readl_relaxed(GICD + GICD_TYPER) & GICD_TYPER_LPIS_SUPPORTED;
 }
 
+static void gicv3_set_irq_properties(struct irq_desc *desc,
+                                     const cpumask_t *cpu_mask,
+                                     unsigned int priority)
+{
+    if ( gic_is_lpi(desc->irq) )
+        its_set_lpi_properties(desc, cpu_mask, priority);
+    else
+        gicv3_set_line_properties(desc, cpu_mask, priority);
+}
+
 static void __init gicv3_dist_init(void)
 {
     uint32_t type;
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index d54bba9..ca115c3 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -72,6 +72,13 @@ bool_t gic_is_lpi(unsigned int irq)
     return (irq >= FIRST_GIC_LPI && irq < gic_nr_irq_ids());
 }
 
+/* Validates PPIs/SGIs/SPIs/LPIs supported */
+bool_t gic_is_valid_irq(unsigned int irq)
+{
+    return (irq < gic_hw_ops->info->nr_lines || gic_is_lpi(irq));
+}
+
+/* Returns number of PPIs/SGIs/SPIs supported */
 unsigned int gic_number_lines(void)
 {
     return gic_hw_ops->info->nr_lines;
@@ -124,7 +131,8 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask,
                           unsigned int priority)
 {
     ASSERT(priority <= 0xff);     /* Only 8 bits of priority */
-    ASSERT(desc->irq < gic_number_lines());/* Can't route interrupts that don't exist */
+    /* Can't route interrupts that don't exist */
+    ASSERT(gic_is_valid_irq(desc->irq));
     ASSERT(test_bit(_IRQ_DISABLED, &desc->status));
     ASSERT(spin_is_locked(&desc->lock));
 
@@ -173,6 +181,26 @@ out:
     return res;
 }
 
+int gic_route_lpi_to_guest(struct domain *d, struct irq_desc *desc,
+                           unsigned int priority)
+{
+    ASSERT(spin_is_locked(&desc->lock));
+
+    desc->handler = gic_hw_ops->gic_get_guest_irq_type(desc->irq);
+    set_bit(_IRQ_GUEST, &desc->status);
+
+    /* Set cpumask to current processor */
+    gic_set_irq_properties(desc, cpumask_of(smp_processor_id()), priority);
+
+    /*
+     * Enable LPI by default. Each pLPI is enabled and routed
+     * when device is assigned.
+     */
+    desc->handler->enable(desc);
+
+    return 0;
+}
+
 /* This function only works with SPIs for now */
 int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
                               struct irq_desc *desc)
@@ -653,7 +681,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
         /* Reading IRQ will ACK it */
         irq = gic_hw_ops->read_irq();
 
-        if ( likely(irq >= 16 && irq < 1020) )
+        if ( likely((irq >= 16 && irq < 1020) || gic_is_lpi(irq)) )
         {
             local_irq_enable();
             do_IRQ(regs, irq, is_fiq);
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index e4c6019..bcb5e0d 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -209,7 +209,7 @@ int request_irq(unsigned int irq, unsigned int irqflags,
      * which interrupt is which (messes up the interrupt freeing
      * logic etc).
      */
-    if ( irq >= nr_irqs )
+    if ( !gic_is_valid_irq(irq) )
         return -EINVAL;
     if ( !handler )
         return -EINVAL;
@@ -267,11 +267,16 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq)
 
         set_bit(_IRQ_INPROGRESS, &desc->status);
 
-        /*
-         * The irq cannot be a PPI, we only support delivery of SPIs to
-         * guests.
-	 */
-        vgic_vcpu_inject_spi(info->d, info->virq);
+#ifdef CONFIG_HAS_GICV3
+        if ( gic_is_lpi(irq) )
+            vgic_vcpu_raise_lpi(info->d, desc);
+        else
+#endif
+            /*
+             * The irq cannot be a PPI, we only support delivery of SPIs to
+             * guests
+             */
+            vgic_vcpu_inject_spi(info->d, info->virq);
         goto out_no_end;
     }
 
@@ -356,6 +361,9 @@ void release_irq(unsigned int irq, const void *dev_id)
     /* Wait to make sure it's not being used on another CPU */
     do { smp_mb(); } while ( test_bit(_IRQ_INPROGRESS, &desc->status) );
 
+    if ( gic_is_lpi(irq) )
+        xfree(desc->msi_desc);
+
     if ( action->free_on_release )
         xfree(action);
 }
@@ -437,9 +445,97 @@ err:
 
 bool_t is_assignable_irq(unsigned int irq)
 {
-    /* For now, we can only route SPIs to the guest */
-    return ((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines()));
+    /* For now, we can only route SPI/LPIs to the guest */
+    return (((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines())) ||
+              gic_is_lpi(irq));
+}
+
+#ifdef CONFIG_HAS_GICV3
+/*
+ * Route an LPI to a specific guest.
+ */
+int route_lpi_to_guest(struct domain *d, unsigned int plpi, const char *devname)
+{
+    struct irqaction *action;
+    struct irq_guest *info;
+    struct irq_desc *desc;
+    unsigned long flags;
+    int retval = 0;
+
+    if ( !gic_is_lpi(plpi) )
+    {
+        printk(XENLOG_G_ERR "Only LPI can be routed \n");
+        return -EINVAL;
+    }
+
+    action = xmalloc(struct irqaction);
+    if ( !action )
+        return -ENOMEM;
+
+    info = xmalloc(struct irq_guest);
+    if ( !info )
+    {
+        xfree(action);
+        return -ENOMEM;
+    }
+    info->d = d;
+
+    action->dev_id = info;
+    action->name = devname;
+    action->free_on_release = 1;
+
+    desc = irq_to_desc(plpi);
+    spin_lock_irqsave(&desc->lock, flags);
+
+    ASSERT(desc->msi_desc != NULL);
+
+    if ( desc->arch.type == DT_IRQ_TYPE_INVALID )
+    {
+        printk(XENLOG_G_ERR "LPI %u has not been configured\n", plpi);
+        retval = -EIO;
+        goto out;
+    }
+
+    /* If the IRQ is already used by same domain, do not setup again.*/
+    if ( desc->action != NULL )
+    {
+        struct domain *ad = irq_get_domain(desc);
+
+        if ( test_bit(_IRQ_GUEST, &desc->status) && d == ad )
+        {
+            printk(XENLOG_G_ERR
+                   "d%u: LPI %u is already assigned to domain %u\n",
+                   d->domain_id, plpi, d->domain_id);
+            retval = -EBUSY;
+            goto out;
+        }
+    }
+
+    retval = __setup_irq(desc, 0, action);
+    if ( retval )
+        goto out;
+
+    retval = gic_route_lpi_to_guest(d, desc, GIC_PRI_IRQ);
+
+    spin_unlock_irqrestore(&desc->lock, flags);
+
+    if ( retval )
+    {
+        release_irq(desc->irq, info);
+        goto free_info;
+    }
+
+    return 0;
+
+out:
+    spin_unlock_irqrestore(&desc->lock, flags);
+    xfree(action);
+free_info:
+    xfree(info);
+
+    return retval;
 }
+#endif
 
 /*
  * Route an IRQ to a specific guest.
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index 41e0b2a..a265452 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -354,7 +354,7 @@ static int vits_process_int(struct vcpu *v, struct vgic_its *vits,
     DPRINTK("%pv: vITS: INT: Device 0x%"PRIx32" id %"PRIu32"\n",
             v, dev_id, event);
 
-    /* TODO: Inject LPI */
+    vgic_vcpu_inject_lpi(v->domain, dev_id, event);
 
     return 0;
 }
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 5b81583..e0ae5a5 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -31,7 +31,9 @@
 
 #include <asm/mmio.h>
 #include <asm/gic.h>
+#include <asm/gic-its.h>
 #include <asm/vgic.h>
+#include <asm/vits.h>
 
 static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, int rank)
 {
@@ -266,13 +268,41 @@ struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq)
 
 static int vgic_get_virq_priority(struct vcpu *v, unsigned int virq)
 {
-    struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
+    struct vgic_irq_rank *rank;
     unsigned long flags;
-    int priority;
+    int priority = 0;
 
-    vgic_lock_rank(v, rank, flags);
-    priority = rank->priority[virq & INTERRUPT_RANK_MASK];
-    vgic_unlock_rank(v, rank, flags);
+    if ( !gic_is_lpi(virq) )
+    {
+        rank = vgic_rank_irq(v, virq);
+
+        vgic_lock_rank(v, rank, flags);
+        priority = rank->priority[virq & INTERRUPT_RANK_MASK];
+        vgic_unlock_rank(v, rank, flags);
+    }
+    else if ( vgic_is_domain_lpi(v->domain, virq) )
+    {
+        /*
+         * Guest can receive LPI before availability of LPI property table.
+         * Hence assert is wrong.
+         * TODO: Handle LPI which is valid and does not have LPI property
+         * table entry and remove below assert.
+         */
+        ASSERT(virq < v->domain->arch.vgic.prop_size);
+
+        spin_lock_irqsave(&v->domain->arch.vgic.prop_lock, flags);
+        /*
+         * LPI property table always starts from 0 (==8192 LPI).
+         * So, subtract 8192 from irq value.
+         */
+        priority = *((u8*)v->domain->arch.vgic.prop_page + virq - FIRST_GIC_LPI);
+        /*
+         * Bits[7:2] specify priority with bits[1:0] of priority
+         * is set to zero. Hence only mask bits[7:2]
+         */
+        priority &= LPI_PRIORITY_MASK;
+        spin_unlock_irqrestore(&v->domain->arch.vgic.prop_lock, flags);
+    }
 
     return priority;
 }
@@ -545,6 +575,69 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq)
     vgic_vcpu_inject_irq(v, virq);
 }
 
+#ifdef CONFIG_HAS_GICV3
+void vgic_vcpu_inject_lpi(struct domain *d, unsigned int vdevid,
+                          unsigned int eventID)
+{
+    struct vdevice_table dt_entry;
+    struct vitt vitt_entry;
+    uint32_t col_id;
+
+    if ( vits_get_vdevice_entry(d, vdevid, &dt_entry) )
+    {
+        dprintk(XENLOG_WARNING,
+                "Failed to read dt entry for dev 0x%"PRIx32" ..dropping\n",
+                vdevid);
+        return;
+    }
+
+    if ( dt_entry.vitt_ipa == INVALID_PADDR )
+    {
+        dprintk(XENLOG_WARNING,
+                "Event %"PRId32" of dev 0x%"PRIx32" is invalid..dropping\n",
+                eventID, vdevid);
+        return;
+    }
+
+    if ( vits_get_vitt_entry(d, vdevid, eventID, &vitt_entry) )
+    {
+        dprintk(XENLOG_WARNING,
+                "Event %"PRId32" of dev 0x%"PRIx32" is invalid..dropping\n",
+                eventID, vdevid);
+        return;
+    }
+
+    col_id = vitt_entry.vcollection;
+
+    if ( !vitt_entry.valid || !is_valid_collection(d, col_id) ||
+         !vgic_is_domain_lpi(d, vitt_entry.vlpi) )
+    {
+        dprintk(XENLOG_WARNING,
+                "vlpi %"PRId32" for dev 0x%"PRIx32" is not valid..dropping\n",
+                vitt_entry.vlpi, vdevid);
+        return;
+    }
+
+    /*
+     * We don't have vlpi to plpi mapping and hence we cannot
+     * have target on which corresponding vlpi is enabled.
+     * So for now we are always injecting vlpi on vcpu0.
+     * (See vgic_vcpu_inject_lpi() function) and so we get pending_irq
+     * structure on vcpu0.
+     * TODO: Get correct target vcpu
+     */
+    vgic_vcpu_inject_irq(d->vcpu[0], vitt_entry.vlpi);
+}
+
+void vgic_vcpu_raise_lpi(struct domain *d, struct irq_desc *desc)
+{
+    struct its_device *dev = irqdesc_get_its_device(desc);
+    unsigned int eventID = irqdesc_get_lpi_event(desc);
+
+    vgic_vcpu_inject_lpi(d, dev->virt_device_id, eventID);
+}
+#endif
+
 void arch_evtchn_inject(struct vcpu *v)
 {
     vgic_vcpu_inject_irq(v, v->domain->arch.evtchn_irq);
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index aad51fa..44919ee 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -303,6 +303,9 @@ int its_init(struct rdist_prop *rdists);
 int its_cpu_init(void);
 int its_add_device(u32 devid, u32 nr_ites, struct dt_device_node *dt_its);
 int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
+void its_set_lpi_properties(struct irq_desc *desc,
+                            const cpumask_t *cpu_mask,
+                            unsigned int priority);
 
 #endif /* __ASM_ARM_GIC_ITS_H__ */
 /*
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index bdcb189..2007e51 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -230,6 +230,9 @@ extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mas
 extern int gic_route_irq_to_guest(struct domain *, unsigned int virq,
                                   struct irq_desc *desc,
                                   unsigned int priority);
+extern int gic_route_lpi_to_guest(struct domain *d,
+                                   struct irq_desc *desc,
+                                   unsigned int priority);
 
 /* Remove an IRQ passthrough to a guest */
 int gic_remove_irq_from_guest(struct domain *d, unsigned int virq,
@@ -286,9 +289,10 @@ extern void send_SGI_allbutself(enum gic_sgi sgi);
 /* print useful debug info */
 extern void gic_dump_info(struct vcpu *v);
 
-/* Number of interrupt lines */
+/* Number of interrupt lines (PPIs + SGIs + SPIs)*/
 extern unsigned int gic_number_lines(void);
-
+/* Check if irq is valid */
+bool_t gic_is_valid_irq(unsigned int irq);
 /* IRQ translation function for the device tree */
 int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
                   unsigned int *out_hwirq, unsigned int *out_type);
diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h
index 323f6c0..7a6fb1c 100644
--- a/xen/include/asm-arm/irq.h
+++ b/xen/include/asm-arm/irq.h
@@ -49,6 +49,8 @@ bool_t is_assignable_irq(unsigned int irq);
 void init_IRQ(void);
 void init_secondary_IRQ(void);
 
+int route_lpi_to_guest(struct domain *d, unsigned int irq,
+                       const char *devname);
 int route_irq_to_guest(struct domain *d, unsigned int virq,
                        unsigned int irq, const char *devname);
 int release_guest_irq(struct domain *d, unsigned int irq);
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 4711d3a..5e194b7 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -305,6 +305,9 @@ extern int vcpu_vgic_init(struct vcpu *v);
 extern struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int virq);
 extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq);
 extern void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq);
+extern void vgic_vcpu_inject_lpi(struct domain *d, unsigned int devid,
+                                 unsigned int eventID);
+extern void vgic_vcpu_raise_lpi(struct domain *d, struct irq_desc *desc);
 extern void vgic_clear_pending_irqs(struct vcpu *v);
 extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq);
 extern struct pending_irq *spi_to_pending(struct domain *d, unsigned int irq);
-- 
1.7.9.5

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

* [PATCH v8 25/28] xen/arm: ITS: Add domain specific ITS initialization
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (23 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 24/28] xen/arm: ITS: Route LPIs vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 26/28] xen/arm: ITS: Map ITS translation space vijayak
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

Call domain specific ITS initialization and introduce
callback in vgic for domain free

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
---
v7: - Deprecate use of gic_lpi_supported and instead use
      vgic_v3_hw.lpi_support
v6: - Moved vits_domain_free() out of this patch
---
 xen/arch/arm/vgic-v3.c     |   12 ++++++++++++
 xen/arch/arm/vgic.c        |    3 +++
 xen/include/asm-arm/vgic.h |    2 ++
 3 files changed, 17 insertions(+)

diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index aa3c5ed..8c1877f 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1830,6 +1830,11 @@ static int vgic_v3_domain_init(struct domain *d)
     d->arch.vgic.ctlr = VGICD_CTLR_DEFAULT;
 
     spin_lock_init(&d->arch.vgic.prop_lock);
+    if ( is_hardware_domain(d) && vgic_v3_hw.its_support )
+    {
+        if ( vits_domain_init(d) )
+            return -ENODEV;
+    }
 
     if ( is_hardware_domain(d) && vgic_v3_hw.its_support )
     {
@@ -1843,9 +1848,16 @@ static int vgic_v3_domain_init(struct domain *d)
     return 0;
 }
 
+void vgic_v3_domain_free(struct domain *d)
+{
+    if ( is_hardware_domain(d) && vgic_v3_hw.its_support )
+        vits_domain_free(d);
+}
+
 static const struct vgic_ops v3_ops = {
     .vcpu_init   = vgic_v3_vcpu_init,
     .domain_init = vgic_v3_domain_init,
+    .domain_free = vgic_v3_domain_free,
     .emulate_sysreg  = vgic_v3_emulate_sysreg,
     /*
      * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index e0ae5a5..c35501b 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -198,6 +198,9 @@ void domain_vgic_free(struct domain *d)
     if ( vgic_is_lpi_supported(d) && d->arch.vgic.prop_page != NULL )
         free_xenheap_pages(d->arch.vgic.prop_page,
                            get_order_from_bytes(d->arch.vgic.prop_size));
+
+    if ( d->arch.vgic.handler->domain_free )
+        d->arch.vgic.handler->domain_free(d);
 }
 
 int vcpu_vgic_init(struct vcpu *v)
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 5e194b7..7c1af7d 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -128,6 +128,8 @@ struct vgic_ops {
     int (*vcpu_init)(struct vcpu *v);
     /* Domain specific initialization of vGIC */
     int (*domain_init)(struct domain *d);
+    /* Free domain specific resources */
+    void (*domain_free)(struct domain *d);
     /* vGIC sysreg emulation */
     int (*emulate_sysreg)(struct cpu_user_regs *regs, union hsr hsr);
     /* Maximum number of vCPU supported */
-- 
1.7.9.5

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

* [PATCH v8 26/28] xen/arm: ITS: Map ITS translation space
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (24 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 25/28] xen/arm: ITS: Add domain specific ITS initialization vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 27/28] xen/arm: ITS: Generate ITS node for Dom0 vijayak
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

ITS translation space contains GITS_TRANSLATER register
which is written by device to raise LPI. This space needs
to mapped to every domain address space for all physical
ITS available,so that device can access GITS_TRANSLATER
register using SMMU.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
---
v7: - Added comment on allowing CPU to access GITS_TRANSLATER
v6: - corrected typo in commit message
    - Removed check for dom0
---
 xen/arch/arm/vgic-v3-its.c |   49 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
index a265452..6809004 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -862,6 +862,53 @@ static const struct mmio_handler_ops vgic_gits_mmio_handler = {
     .write = vgic_v3_gits_mmio_write,
 };
 
+/*
+ * Map the 64K ITS translation space in guest.
+ * This is required purely for device smmu writes.
+*/
+
+static int vits_map_translation_space(struct domain *d)
+{
+    uint64_t addr, size;
+    int ret;
+
+    ASSERT(is_domain_direct_mapped(d));
+
+    addr = d->arch.vgic.vits->gits_base + SZ_64K;
+    size = SZ_64K;
+
+    /* For DomU translation space is mapped 1:1.
+     *
+     * As per spec IHI0069A, 8.1.3 there is undefined behavior when CPU
+     * writes to this register with wrong access size.
+     * Currently the page table are shared between the processor and the SMMU,
+     * So that means that a domain will be able to deadlock the processor
+     * and therefore the whole platform.
+     *
+     * TODO: A CPU should *never* be able to write to the GITS_TRANSLATER
+     * register. We have to make sure a guest cannot directly write to the HW.
+     * So we should never expose GITS_TRANSLATER into the processor page table.
+     * Which means we should not share page tables between the processor
+     * and the SMMU
+     *
+     * TODO: Also Handle DomU mapping
+     */
+    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 )
+    {
+         dprintk(XENLOG_G_ERR, "vITS: Unable to map to"
+                 " 0x%"PRIx64" - 0x%"PRIx64" to dom%d\n",
+                 addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1,
+                 d->domain_id);
+    }
+
+    return ret;
+}
+
 int vits_domain_init(struct domain *d)
 {
     struct vgic_its *vits;
@@ -921,7 +968,7 @@ int vits_domain_init(struct domain *d)
     register_mmio_handler(d, &vgic_gits_mmio_handler, vits->gits_base,
                           SZ_64K, NULL);
 
-    return 0;
+    return vits_map_translation_space(d);
 }
 
 void vits_domain_free(struct domain *d)
-- 
1.7.9.5

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

* [PATCH v8 27/28] xen/arm: ITS: Generate ITS node for Dom0
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (25 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 26/28] xen/arm: ITS: Map ITS translation space vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-02-01  9:26 ` [PATCH v8 28/28] xen/arm: ITS: Add pci devices in ThunderX vijayak
  2016-04-08 13:42 ` [PATCH v8 00/28] Add ITS support Steve Capper
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, 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>
---
v7: - Check on return value
v6: - Introduced get_its_phandle in gic_hw_ops
    - Removed make_hwdom_its_dt_node callback in gic_hw_ops
    - Renamed gic_get_msi_handle() as gic_update_msi_phandle()
    - Renamed its_get_phandle to its_update_phandle()
    - ITS node generation is wrapped inside GICv3
    - Update msi-parent phandle only if msi-parent is ITS
      and find its phandle on demand
v5: - Moved ITS dt node generation to ITS driver
v4: - Generate only one ITS node for Dom0
    - Replace msi-parent references to single its phandle
---
 xen/arch/arm/domain_build.c   |   14 +++++
 xen/arch/arm/gic-v3-its.c     |  120 +++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c         |   17 +++++-
 xen/arch/arm/gic.c            |    8 +++
 xen/include/asm-arm/gic-its.h |    2 +
 xen/include/asm-arm/gic.h     |    5 +-
 6 files changed, 164 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 0f0f53e..0c39846 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -468,6 +468,20 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo,
             continue;
         }
 
+        /*
+         * Replace all msi-parent phandle references to single ITS node
+         * generated for Dom0
+         */
+        if ( dt_property_name_is_equal(prop, "msi-parent") )
+        {
+            DPRINT(" Set msi-parent with ITS phandle (if ITS available)\n");
+            res = gic_update_msi_phandle(kinfo->fdt, prop);
+            if ( res )
+                return res;
+
+            continue;
+        }
+
         res = fdt_property(kinfo->fdt, prop->name, prop_data, prop_len);
 
         if ( res )
diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c
index cbf517a..2a73b00 100644
--- a/xen/arch/arm/gic-v3-its.c
+++ b/xen/arch/arm/gic-v3-its.c
@@ -27,6 +27,8 @@
 #include <xen/sched.h>
 #include <xen/errno.h>
 #include <xen/delay.h>
+#include <xen/device_tree.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/list.h>
 #include <xen/sizes.h>
 #include <xen/vmap.h>
@@ -1303,6 +1305,124 @@ static void its_cpu_init_collection(void)
     spin_unlock(&its_lock);
 }
 
+int its_make_dt_node(const struct domain *d, void *fdt)
+{
+    struct its_node *its;
+    const struct dt_device_node *node;
+    const void *compatible = NULL;
+    u32 len;
+    __be32 *new_cells, *tmp;
+    int res = 0;
+
+    /* Will pass only first ITS node info */
+    its = list_first_entry(&its_nodes, struct its_node, entry);
+    if ( !its )
+    {
+        dprintk(XENLOG_ERR, "ITS node not found\n");
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    node = its->dt_node;
+
+    compatible = dt_get_property(node, "compatible", &len);
+    if ( !compatible )
+    {
+        dprintk(XENLOG_ERR, "Can't find compatible property for the its 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, its->phys_base, its->phys_size);
+
+    res = fdt_property(fdt, "reg", new_cells, len);
+    xfree(new_cells);
+    if ( res )
+        return res;
+
+    if ( node->phandle )
+    {
+        res = fdt_property_cell(fdt, "phandle", node->phandle);
+        if ( res )
+            return res;
+    }
+
+    res = fdt_end_node(fdt);
+
+    return res;
+}
+
+static int its_find_compatible_phandle(fdt32_t msi_parent_phandle)
+{
+    struct its_node *its;
+    const struct dt_device_node *node;
+    fdt32_t phandle;
+
+    list_for_each_entry(its, &its_nodes, entry)
+    {
+        node = its->dt_node;
+
+        if ( node->phandle )
+        {
+            phandle = cpu_to_fdt32(node->phandle);
+            if ( phandle == msi_parent_phandle )
+               return 0;
+        }
+    }
+
+    return -FDT_ERR_XEN(ENOENT);
+}
+
+int its_update_phandle(void *fdt, const struct dt_property *prop)
+{
+    struct its_node *its;
+    const struct dt_device_node *node;
+    fdt32_t phandle, msi_parent_phandle;
+
+    memcpy(&msi_parent_phandle, prop->value, sizeof(msi_parent_phandle));
+
+    /* chech if msi-parent phandle is ITS */
+    if ( its_find_compatible_phandle(msi_parent_phandle) )
+        return -FDT_ERR_XEN(ENOENT);
+
+    /* Only first ITS node phandle is considered */
+    its = list_first_entry(&its_nodes, struct its_node, entry);
+    if ( !its )
+    {
+        dprintk(XENLOG_ERR, "ITS node not found\n");
+        return -FDT_ERR_XEN(ENOENT);
+    }
+
+    node = its->dt_node;
+
+    if ( node->phandle )
+    {
+        phandle = cpu_to_fdt32(node->phandle);
+        fdt_property(fdt, prop->name, (void *)&phandle, sizeof(phandle));
+
+        return 0;
+    }
+
+    return -FDT_ERR_XEN(ENOENT);
+}
+
 static int its_force_quiescent(void __iomem *base)
 {
     u32 count = 1000000;   /* 1s */
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 47e6b8a..df8f594 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1124,6 +1124,14 @@ static void gicv3_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
     spin_unlock(&gicv3.lock);
 }
 
+static int gicv3_update_its_phandle(void *fdt, const struct dt_property *prop)
+{
+    if ( its_enabled )
+        return its_update_phandle(fdt, prop);
+
+    return 0;
+}
+
 static int gicv3_make_hwdom_dt_node(const struct domain *d,
                                     const struct dt_device_node *gic,
                                     void *fdt)
@@ -1144,6 +1152,10 @@ static int gicv3_make_hwdom_dt_node(const struct domain *d,
     if ( res )
         return res;
 
+    res = fdt_property(fdt, "ranges", NULL, 0);
+    if ( res )
+        return res;
+
     res = fdt_property_cell(fdt, "redistributor-stride",
                             d->arch.vgic.rdist_stride);
     if ( res )
@@ -1175,8 +1187,10 @@ static int gicv3_make_hwdom_dt_node(const struct domain *d,
 
     res = fdt_property(fdt, "reg", new_cells, len);
     xfree(new_cells);
+    if ( res )
+        return res;
 
-    return res;
+    return its_make_dt_node(d, fdt);
 }
 
 static const hw_irq_controller gicv3_host_irq_type = {
@@ -1424,6 +1438,7 @@ static const struct gic_hw_operations gicv3_ops = {
     .read_vmcr_priority  = gicv3_read_vmcr_priority,
     .read_apr            = gicv3_read_apr,
     .secondary_init      = gicv3_secondary_cpu_init,
+    .update_its_phandle  = gicv3_update_its_phandle,
     .make_hwdom_dt_node  = gicv3_make_hwdom_dt_node,
 };
 
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index ca115c3..a8a87c9 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -739,6 +739,14 @@ void init_maintenance_interrupt(void)
                 "irq-maintenance", NULL);
 }
 
+int gic_update_msi_phandle(void *fdt, const struct dt_property *prop)
+{
+    if ( gic_hw_ops->update_its_phandle != NULL )
+        return gic_hw_ops->update_its_phandle(fdt, prop);
+
+    return 0;
+}
+
 int gic_make_hwdom_dt_node(const struct domain *d,
                            const struct dt_device_node *gic,
                            void *fdt)
diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
index 44919ee..587844d 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -306,6 +306,8 @@ int its_assign_device(struct domain *d, u32 vdevid, u32 pdevid);
 void its_set_lpi_properties(struct irq_desc *desc,
                             const cpumask_t *cpu_mask,
                             unsigned int priority);
+int its_update_phandle(void *fdt, const struct dt_property *prop);
+int its_make_dt_node(const struct domain *d, 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 2007e51..1d8075c 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -156,6 +156,7 @@
 
 #ifndef __ASSEMBLY__
 #include <xen/device_tree.h>
+#include <xen/libfdt/libfdt.h>
 #include <xen/irq.h>
 #include <asm-arm/vgic.h>
 
@@ -365,7 +366,8 @@ struct gic_hw_operations {
     int (*secondary_init)(void);
     /* Create GIC node for the hardware domain */
     int (*make_hwdom_dt_node)(const struct domain *d,
-                              const struct dt_device_node *gic, void *fdt);
+                              const struct dt_device_node *node, void *fdt);
+    int (*update_its_phandle)(void *fdt, const struct dt_property *prop);
 };
 
 void register_gic_ops(const struct gic_hw_operations *ops);
@@ -374,6 +376,7 @@ int gic_make_hwdom_dt_node(const struct domain *d,
                            void *fdt);
 unsigned int gic_nr_irq_ids(void);
 bool_t gic_is_lpi(unsigned int irq);
+int gic_update_msi_phandle(void *fdt, const struct dt_property *prop);
 
 #endif /* __ASSEMBLY__ */
 #endif
-- 
1.7.9.5

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

* [PATCH v8 28/28] xen/arm: ITS: Add pci devices in ThunderX
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (26 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 27/28] xen/arm: ITS: Generate ITS node for Dom0 vijayak
@ 2016-02-01  9:26 ` vijayak
  2016-04-08 13:42 ` [PATCH v8 00/28] Add ITS support Steve Capper
  28 siblings, 0 replies; 31+ messages in thread
From: vijayak @ 2016-02-01  9:26 UTC (permalink / raw)
  To: Ian.Campbell, julien.grall, stefano.stabellini,
	stefano.stabellini, tim, xen-devel
  Cc: Prasun.Kapoor, manish.jaggi, Vijaya Kumar K, vijay.kilari

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

ITS initialization required for all PCI devices in
ThunderX platform are done by calling from specific
mapping function.

This patch can be reverted once XEN PCI passthrough
framework for arm64 is in available.

For now all the PCI devices are assigned to Dom0

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
---
v7: Calculate size of bdf[] instead of hardcoding count
---
 xen/arch/arm/platforms/Makefile   |    1 +
 xen/arch/arm/platforms/thunderx.c |  200 +++++++++++++++++++++++++++++++++++++
 2 files changed, 201 insertions(+)

diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile
index e173fec..d9f98f9 100644
--- a/xen/arch/arm/platforms/Makefile
+++ b/xen/arch/arm/platforms/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_ARM_32) += sunxi.o
 obj-$(CONFIG_ARM_32) += rcar2.o
 obj-$(CONFIG_ARM_64) += seattle.o
 obj-$(CONFIG_ARM_64) += xgene-storm.o
+obj-$(CONFIG_ARM_64) += thunderx.o
diff --git a/xen/arch/arm/platforms/thunderx.c b/xen/arch/arm/platforms/thunderx.c
new file mode 100644
index 0000000..1557d98
--- /dev/null
+++ b/xen/arch/arm/platforms/thunderx.c
@@ -0,0 +1,200 @@
+/*
+ * xen/arch/arm/platforms/thunderx.c
+ *
+ * Cavium Thunder specific settings
+ *
+ * Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
+ * Copyright (c) 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <xen/config.h>
+#include <asm/platform.h>
+#include <asm/gic-its.h>
+
+struct pci_dev_list 
+{
+   uint32_t seg;
+   uint32_t bus;
+   uint32_t dev;
+   uint32_t func;
+};
+
+static struct pci_dev_list bdf[] =
+{
+    {0, 0, 1, 0},
+    {0, 0, 2, 0},
+    {0, 0, 6, 0},
+    {0, 0, 7, 0},
+    {0, 0, 10, 0},
+    {0, 0, 11, 0},
+    {0, 0, 14, 0},
+    {0, 0, 15, 0},
+    {0, 0, 16, 0},
+    {0, 1, 0, 0},
+    {0, 1, 0, 1},
+    {0, 1, 0, 5},
+    {0, 1, 1, 4},
+    {0, 1, 9, 0},
+    {0, 1, 9, 1},
+    {0, 1, 9, 2},
+    {0, 1, 9, 3},
+    {0, 1, 9, 4},
+    {0, 1, 9, 5},
+    {0, 1, 10, 0},
+    {0, 1, 10, 1},
+    {0, 1, 10, 2},
+    {0, 1, 10, 3},
+    {0, 1, 14, 0},
+    {0, 1, 14, 2},
+    {0, 1, 14, 4},
+    {0, 1, 16, 0},
+    {0, 1, 16, 1},
+    {0, 2, 0, 0},
+    {0, 3, 0, 0},
+    {0, 4, 0, 0},
+    {1, 0, 1, 0},
+    {1, 0, 4, 0},
+    {1, 0, 5, 0},
+    {1, 0, 6, 0},
+    {1, 0, 7, 0},
+    {1, 0, 8, 0},
+    {1, 0, 9, 0},
+    {1, 0, 10, 0},
+    {1, 0, 11, 0},
+    {2, 0, 1, 0},
+    {2, 0, 2, 0},
+    {2, 0, 3, 0},
+    {2, 1, 0, 0},
+    {2, 1, 0, 1},
+    {2, 1, 0, 2},
+    {2, 1, 0, 3},
+    {2, 1, 0, 4},
+    {2, 1, 0, 5},
+    {2, 1, 0, 6},
+    {2, 1, 0, 7},
+    {2, 1, 1, 0},
+    {2, 1, 1, 1},
+    {2, 1, 1, 2},
+    {2, 1, 1, 3},
+    {2, 1, 1, 4},
+    {2, 1, 1, 5},
+    {2, 1, 1, 6},
+    {2, 1, 1, 7},
+    {2, 1, 2, 0},
+    {2, 1, 2, 1},
+    {2, 1, 2, 2},
+    {2, 1, 2, 3},
+    {2, 1, 2, 4},
+    {2, 1, 2, 5},
+    {2, 1, 2, 6},
+    {2, 1, 2, 7},
+    {2, 1, 3, 0},
+    {2, 1, 3, 1},
+    {2, 1, 3, 2},
+    {2, 1, 3, 3},
+    {2, 1, 3, 4},
+    {2, 1, 3, 5},
+    {2, 1, 3, 6},
+    {2, 1, 3, 7},
+    {2, 1, 4, 0},
+    {2, 1, 4, 1},
+    {2, 1, 4, 2},
+    {2, 1, 4, 3},
+    {2, 1, 4, 4},
+    {2, 1, 4, 5},
+    {2, 1, 4, 6},
+    {2, 1, 4, 7},
+    {2, 1, 5, 0},
+    {2, 1, 5, 1},
+    {2, 1, 5, 2},
+    {2, 1, 5, 3},
+    {2, 1, 5, 4},
+    {2, 1, 5, 5},
+    {2, 1, 5, 6},
+    {2, 1, 5, 7},
+    {2, 1, 6, 0},
+    {2, 1, 6, 1},
+    {2, 1, 6, 2},
+    {2, 1, 6, 3},
+    {2, 1, 6, 4},
+    {2, 1, 6, 5},
+    {2, 1, 6, 6},
+    {2, 1, 6, 7},
+    {2, 1, 7, 0},
+    {2, 1, 7, 1},
+    {2, 1, 7, 2},
+    {2, 1, 7, 3},
+    {2, 1, 7, 4},
+    {3, 0, 1, 0},
+};
+
+#define BDF_TO_DEVID(seg, bus, dev, func) (seg << 16 | bus << 8 | dev << 3| func)
+
+/* TODO: add and assign devices using PCI framework */
+static int thunderx_specific_mapping(struct domain *d)
+{
+    struct dt_device_node *dt_its;
+    uint32_t devid, i;
+    int res;
+
+    static const struct dt_device_match its_device_ids[] __initconst =
+    {
+        DT_MATCH_GIC_ITS,
+        { /* sentinel */ },
+    };
+
+    for (dt_its = dt_find_matching_node(NULL, its_device_ids); dt_its;
+           dt_its = dt_find_matching_node(dt_its, its_device_ids))
+    {
+        break;
+    }
+
+    if ( dt_its == NULL )
+    {
+        dprintk(XENLOG_ERR, "ThunderX: ITS node not found to add device\n");
+        return 0;
+    }
+
+    for ( i = 0; i < ARRAY_SIZE(bdf); i++ )
+    {
+        devid = BDF_TO_DEVID(bdf[i].seg, bdf[i].bus,bdf[i].dev, bdf[i].func);
+        res = its_add_device(devid, 32, dt_its);
+        if ( res )
+            return res;
+        res = its_assign_device(d, devid, devid);
+        if ( res )
+            return res;
+    }
+
+    return 0;
+}
+
+static const char * const thunderx_dt_compat[] __initconst =
+{
+    "cavium,thunder-88xx",
+    NULL
+};
+
+PLATFORM_START(thunderx, "THUNDERX")
+    .compatible = thunderx_dt_compat,
+    .specific_mapping = thunderx_specific_mapping,
+PLATFORM_END
+
+/*
+ * 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] 31+ messages in thread

* Re: [PATCH v8 00/28] Add ITS support
  2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
                   ` (27 preceding siblings ...)
  2016-02-01  9:26 ` [PATCH v8 28/28] xen/arm: ITS: Add pci devices in ThunderX vijayak
@ 2016-04-08 13:42 ` Steve Capper
  2016-04-09 23:25   ` Stefano Stabellini
  28 siblings, 1 reply; 31+ messages in thread
From: Steve Capper @ 2016-04-08 13:42 UTC (permalink / raw)
  To: vijayak
  Cc: prasun.kapoor, andre.przywara, julien.grall, sstabellini, xen-devel

Hello,
We are going to re-examine the design document behind GICv3 ITS within
ARM to see if any simplifications can be made. This should, in turn,
help us simplify this series somewhat.

The revised design document will then be sent to xen-devel for review
before we re-examine this series.

Cheers,
-- 
Steve Capper

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH v8 00/28] Add ITS support
  2016-04-08 13:42 ` [PATCH v8 00/28] Add ITS support Steve Capper
@ 2016-04-09 23:25   ` Stefano Stabellini
  0 siblings, 0 replies; 31+ messages in thread
From: Stefano Stabellini @ 2016-04-09 23:25 UTC (permalink / raw)
  To: Steve Capper
  Cc: sstabellini, vijayak, andre.przywara, xen-devel, prasun.kapoor,
	julien.grall

Sounds good. Thank you.

Cheers,

Stefano

On Fri, 8 Apr 2016, Steve Capper wrote:
> Hello,
> We are going to re-examine the design document behind GICv3 ITS within
> ARM to see if any simplifications can be made. This should, in turn,
> help us simplify this series somewhat.
> 
> The revised design document will then be sent to xen-devel for review
> before we re-examine this series.
> 
> Cheers,
> -- 
> Steve Capper
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

end of thread, other threads:[~2016-04-09 23:25 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-01  9:26 [PATCH v8 00/28] Add ITS support vijayak
2016-02-01  9:26 ` [PATCH v8 01/28] xen/arm: Add bitmap_find_next_zero_area helper function vijayak
2016-02-01  9:26 ` [PATCH v8 02/28] xen: Add log2 functionality vijayak
2016-02-01  9:26 ` [PATCH v8 03/28] xen/arm: Set nr_cpu_ids to available number of cpus vijayak
2016-02-01  9:26 ` [PATCH v8 04/28] xen/arm: Rename NR_IRQs and vgic_num_irqs helper function vijayak
2016-02-01  9:26 ` [PATCH v8 05/28] xen/arm: ITS: Port ITS driver to Xen vijayak
2016-02-01  9:26 ` [PATCH v8 06/28] xen/arm: ITS: Add helper functions to manage its_devices vijayak
2016-02-01  9:26 ` [PATCH v8 07/28] xen/arm: ITS: Introduce msi_desc for LPIs vijayak
2016-02-01  9:26 ` [PATCH v8 08/28] xen/arm: ITS: Add APIs to add and assign device vijayak
2016-02-01  9:26 ` [PATCH v8 09/28] xen/arm: ITS: Introduce gic_is_lpi helper function vijayak
2016-02-01  9:26 ` [PATCH v8 10/28] xen/arm: ITS: Implement hw_irq_controller for LPIs vijayak
2016-02-01  9:26 ` [PATCH v8 11/28] xen/arm: ITS: Enable compilation of physical ITS driver vijayak
2016-02-01  9:26 ` [PATCH v8 12/28] xen/arm: ITS: Plumb hw_irq_controller for LPIs vijayak
2016-02-01  9:26 ` [PATCH v8 13/28] xen/arm: Correct GICD_TYPER register definition typos vijayak
2016-02-01  9:26 ` [PATCH v8 14/28] xen/arm: ITS: Initialize physical ITS and export lpi support vijayak
2016-02-01  9:26 ` [PATCH v8 15/28] xen/arm: ITS: Add virtual ITS driver vijayak
2016-02-01  9:26 ` [PATCH v8 16/28] xen/arm: ITS: Add virtual ITS commands support vijayak
2016-02-01  9:26 ` [PATCH v8 17/28] xen/arm: ITS: Add GITS registers emulation vijayak
2016-02-01  9:26 ` [PATCH v8 18/28] xen/arm: ITS: Export ITS info to Virtual ITS vijayak
2016-02-01  9:26 ` [PATCH v8 19/28] xen/arm: ITS: Store the number of LPIs allocated per domain vijayak
2016-02-01  9:26 ` [PATCH v8 20/28] xen/arm: ITS: Add virtual ITS availability check helper vijayak
2016-02-01  9:26 ` [PATCH v8 21/28] xen/arm: ITS: Add GICR register emulation vijayak
2016-02-01  9:26 ` [PATCH v8 22/28] xen/arm: ITS: Allocate irq descriptors for LPIs vijayak
2016-02-01  9:26 ` [PATCH v8 23/28] xen/arm: ITS: Allocate pending_lpi " vijayak
2016-02-01  9:26 ` [PATCH v8 24/28] xen/arm: ITS: Route LPIs vijayak
2016-02-01  9:26 ` [PATCH v8 25/28] xen/arm: ITS: Add domain specific ITS initialization vijayak
2016-02-01  9:26 ` [PATCH v8 26/28] xen/arm: ITS: Map ITS translation space vijayak
2016-02-01  9:26 ` [PATCH v8 27/28] xen/arm: ITS: Generate ITS node for Dom0 vijayak
2016-02-01  9:26 ` [PATCH v8 28/28] xen/arm: ITS: Add pci devices in ThunderX vijayak
2016-04-08 13:42 ` [PATCH v8 00/28] Add ITS support Steve Capper
2016-04-09 23:25   ` Stefano Stabellini

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.