All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/39] New VGIC(-v2) implementation
@ 2018-03-21 16:31 Andre Przywara
  2018-03-21 16:31 ` [PATCH v3 01/39] xen/arm: gic: Read unconditionally the source from the LRs Andre Przywara
                   ` (38 more replies)
  0 siblings, 39 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:31 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Jan Beulich, Andrew Cooper

tl;dr: Coarse changelog below, individual patches have changelogs as
well.

Yet another update, the number of changes getting smaller again. Another
round of patches have been merged already. Mostly smaller reworks now,
as usual addressing the comments. Noticeable changes are the inclusion
of the physical timer in our level IRQ update routine (patch 05/39) and
the reworked _IRQ_INPROGRESS setting on tweaking the active or pending
state (patch 03/39), along with some build system improvements.
For a detailed list of changes see below, also each individual patch has
its own changelog as well.
Patches without Reviewed-by: or Acked-by: tags are:
02, 03, 05, 09, 11, 13, 14, 15, 18, 25, 34, 36, 38, 39

There are some things that have (still) not been covered yet:
- struct VCPU still allocates two pages on ARM64 when using the new VGIC now.
We could try to look if we can allocate some parts of struct vcpu instead of
embedding sub-structures into it.
- vGICv3 support is not implemented, but should be fairly straight-forward to
add, as the design incorporated this already. Will look at this next.
- There is a possible DOS vector on the VCPU ap_list, which holds pending
vIRQs. A guest can make this list rather long, which forces the hypervisor
to hold the list lock when iterating the list. This should be bounded by
the number of emulated vIRQs though, and there are ideas how to mitigate
this issue. Those fixes would be posted on top as fixes later.
- There is no ITS support, though the VGIC code itself is more ready for that
than the old VGIC ever was. However due to differences between the Xen
and KVM architecture the ITS bits are not easy to port over to Xen.

Cheers,
Andre

=====================
During development of the Dom0 ITS MSI support last year we realised
that the existing GIC interrupt controller emulation has some shortcomings.
After some tries to fix those in the existing code, it was agreed upon
that the problems are fundamental and a new implementation based on the
"new VGIC" in KVM is the best choice.
This is this new VGIC implementation, based on the (heavily modified)
KVM version. It lives in the xen/arch/arm/vgic/ directory and is written
to be a compile time option, so people can choose whether to use the new
VGIC or the existing implementation. This is just for a transitional period,
the old VGIC is expected to be removed after confidence in the new
implementation has grown.

This series starts with some cleanup and refactoring patches for the
existing VGIC/GIC code, this includes preparations to properly support
level triggered interrupts. This is one of the biggest problems in the
existing VGIC, which only correctly emulates edge triggered IRQs. This
affects both arch code and some users like the timer and the event channel.

Starting with patch 08 we plumb in the new VGIC then. This is done in a
new directory, with all the files actually not wired into the build system
until the very last patch. The idea is to split the series into reviewable
chunks without resorting to nasty hacks to keep bisectability.
The code was forked from Linux' virt/kvm/arm/vgic/, as of 4.14-rc7, plus
some recent changes to improve support for level triggered and hardware
mapped interrupts, which is what we use heavily in Dom0. The code was
heavily adapted to fit into Xen, starting with using the Xen coding style
and using Xen structure and variable names (struct domain instead of
struct kvm, for instance). Where interfacing functions were similar enough,
they were changed over to the existing Xen name and prototypes (for instance
kvm_vgic_create() was renamed to domain_vgic_register()). As far as possible
the code layout and split was re-used from KVM, so patches in Linux should
be relatively easy to port into Xen. Due to the mentioned changes this can
not be done easily in an automatic way, but it should be not too complicated
to extract the gist of the patch and re-apply this to our code base.

The actual VGIC code splits into several parts:
- The core is the struct vgic_irq, which holds every information about a
virtual IRQ, including a per-IRQ lock. Also there is on (ordered) per-VCPU
list (ap_list), which links the interrupts to be considered by a VCPU.
There are functions to deal with queuing and removing IRQs from those lists
safely, obeying the locking order. (patches 08-12)
- There are functions to push vIRQs on a VCPU list to the list registers,
and handle their state changes. (patches 13-15)
- The distributor MMIO emulation is using separate functions per register,
also having read and write split. (patches 16-26)
- There are functions to deal with Xen specialities. (patches 27-33)
- The data structures and the wiring of the emulation into the hypervisor
  and the guests are done in vgic-init.c. (patches 34-37)
- Finally patch 39 enables the build of the new VGIC. This requires to
  increase the size limit for struct vcpu in patch 38.

Andre

Changelog v2 ... v3:
- removing already merged patches
- prepending Julien's patch to fix a regression with some of the earlier merged
  preparatory patches
- adding GIC_INVALID member to enum gic_version
- reworking the arch timer IRQ update code
- reworking the _IRQ_INPROGRESS setting
- reworking list_sort build system inclusion
- replace various occurences of 0/1 with false/true
- clear _IRQ_INPROGRESS bit when retiring hardware mapped IRQ
- fix target mask calculation in SGI injection
- detect uninitialised VGIC in vgic_max_vcpus()
- fix nr_spis ROUNDUP
- reworking struct vcpu allocation checks
- adding various ACKs and R-b's. Thanks to the reviewers!
- extending and adding comments, whitespace fixes

Changelog v1 ... v2:
- add VCPU parameter to renamed gic_event_needs_delivery()
- use vcpu_kick, using existing x86 prototype
- include Julien's struct gic_lr rework series
- extend setting of _IRQ_INPROGRESS when tweaking active/pending state
- restrict level IRQ device handling to new VGIC
- cleanup vgic.h
- make vgic_inject_irq() and sync_{to,from}_lr() functions return void
- add dropped code to properly handle 
- split off introduction of Linux' list_sort() into separate patch
- fix handling of multiple-source-SGIs, as done in Linux recently
- use KVM IIDR identifier, but use different variant for Xen
- ASSERT that association between hardware and virtual IRQs do not change
- print warning on every IRQ failing to set/clear active bit
- avoid unneeded calls to vgic_sync_hardware_irq(), avoiding desc lock
- fixup wrong number of SPIs (not a multiple of 32)
- move vgic_v2_enable patch around
- confine two 4K pages for struct vcpu to new VGIC and ARM64
- use separate Makefile for new VGIC
- enhance Kconfig help text
- many whitespace and indentation fixes
- using more unsigned ints
- adding and extending comments

Changelog RFC ... v1:
- observe review comments on GICv3 redistributor patches
- implement physical-follows-virtual IRQ affinity
- actually implement arch_move_irq()
- move max_domain_vcpus() into vgic.c, to make it VGIC specific
- improved many commit messages
- add ACKs so far
- added and extended many comments
- use C99 data types (uint32_t)
- use unsigned data types
- use symbolic names for constants
- white space fixes (indentation mostly)
- adapt later patches to changes earlier in the series (renames etc.)
- use 32 bit data types where sufficient
- add helper functions as requested (for instance gicv2/3_peek/poke_irq)
- use struct irq_desc * in interface of hardware facing functions
- rename some existing Xen function names to be more readable
- rename new header file from arm_vgic.h to new_vgic.h
- drop code or variables dealing with unimplemented features (ITS, CPU i/f)
- reorder struct vgic_irq and use bitfield to shrink data structure size
- remove not needed functions (gic_clear_lrs(), save/restore_state())
- add ASSERTS as requested
- add locking where missing (dump_vgic_info, read pending state, enabling GIC)
- keep Linux coding style for list_sort.c
- add set_pending_state() GIC abstraction function
- factor out and use kick_vcpu()
- use frame number instead of physical address
- use existing LR accessor functions, drop GICH_ accesses from vgic-v2.c
- skip already disabled/enabled IRQs and setting enabled state
- use PRODUCT_ID_XEN
- simplify and clarify on ACTIVE bit MMIO accesses
- use interface for HCR bit changes
- iterate over set CPU bits in SGI injection handler

Andre Przywara (38):
  ARM: GIC: add GIC_INVALID to enum gic_version
  ARM: GIC: Allow tweaking the active and pending state of an IRQ
  ARM: GIC: Allow reading pending state of a hardware IRQ
  ARM: timer: Handle level triggered IRQs correctly
  ARM: evtchn: Handle level triggered IRQs correctly
  ARM: vPL011: Use the VGIC's level triggered IRQs handling if available
  ARM: new VGIC: Add data structure definitions
  ARM: new VGIC: Add accessor to new struct vgic_irq instance
  ARM: new VGIC: Implement virtual IRQ injection
  Add list_sort() routine from Linux
  ARM: new VGIC: Add IRQ sorting
  ARM: new VGIC: Add IRQ sync/flush framework
  ARM: new VGIC: Add GICv2 world switch backend
  ARM: new VGIC: Implement vgic_vcpu_pending_irq
  ARM: new VGIC: Add MMIO handling framework
  ARM: new VGIC: Add GICv2 MMIO handling framework
  ARM: new VGIC: Add CTLR, TYPER and IIDR handlers
  ARM: new VGIC: Add ENABLE registers handlers
  ARM: new VGIC: Add PENDING registers handlers
  ARM: new VGIC: Add ACTIVE registers handlers
  ARM: new VGIC: Add PRIORITY registers handlers
  ARM: new VGIC: Add CONFIG registers handlers
  ARM: new VGIC: Add TARGET registers handlers
  ARM: new VGIC: Add SGIR register handler
  ARM: new VGIC: Add SGIPENDR register handlers
  ARM: new VGIC: Handle hardware mapped IRQs
  ARM: new VGIC: Add event channel IRQ handling
  ARM: new VGIC: Handle virtual IRQ allocation/reservation
  ARM: new VGIC: Dump virtual IRQ info
  ARM: new VGIC: Provide system register emulation stub
  ARM: new VGIC: Implement arch_move_irqs()
  ARM: new VGIC: Add preliminary stub implementation
  ARM: new VGIC: vgic-init: register VGIC
  ARM: new VGIC: Add vgic_v2_enable
  ARM: new VGIC: vgic-init: implement vgic_init
  ARM: new VGIC: vgic-init: implement map_resources
  ARM: new VGIC: Allocate two pages for struct vcpu
  ARM: VGIC: wire new VGIC(-v2) files into Xen build system

Julien Grall (1):
  xen/arm: gic: Read unconditionally the source from the LRs

 xen/arch/arm/Kconfig             |   18 +-
 xen/arch/arm/Makefile            |    5 +-
 xen/arch/arm/domain.c            |   32 +-
 xen/arch/arm/gic-v2.c            |   66 ++-
 xen/arch/arm/gic-v3.c            |   64 ++-
 xen/arch/arm/traps.c             |   12 +
 xen/arch/arm/vgic/Makefile       |    5 +
 xen/arch/arm/vgic/vgic-init.c    |  261 ++++++++++
 xen/arch/arm/vgic/vgic-mmio-v2.c |  321 ++++++++++++
 xen/arch/arm/vgic/vgic-mmio.c    |  639 ++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    |  138 ++++++
 xen/arch/arm/vgic/vgic-v2.c      |  311 ++++++++++++
 xen/arch/arm/vgic/vgic.c         | 1001 ++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.h         |   83 ++++
 xen/arch/arm/vpl011.c            |    4 +
 xen/arch/arm/vtimer.c            |   49 ++
 xen/common/Kconfig               |    3 +
 xen/common/Makefile              |    1 +
 xen/common/list_sort.c           |  157 ++++++
 xen/include/asm-arm/event.h      |    1 +
 xen/include/asm-arm/gic.h        |   36 ++
 xen/include/asm-arm/new_vgic.h   |  198 ++++++++
 xen/include/asm-arm/vgic.h       |    6 +
 xen/include/asm-arm/vtimer.h     |    1 +
 xen/include/xen/list_sort.h      |   11 +
 25 files changed, 3405 insertions(+), 18 deletions(-)
 create mode 100644 xen/arch/arm/vgic/Makefile
 create mode 100644 xen/arch/arm/vgic/vgic-init.c
 create mode 100644 xen/arch/arm/vgic/vgic-mmio-v2.c
 create mode 100644 xen/arch/arm/vgic/vgic-mmio.c
 create mode 100644 xen/arch/arm/vgic/vgic-mmio.h
 create mode 100644 xen/arch/arm/vgic/vgic-v2.c
 create mode 100644 xen/arch/arm/vgic/vgic.c
 create mode 100644 xen/arch/arm/vgic/vgic.h
 create mode 100644 xen/common/list_sort.c
 create mode 100644 xen/include/asm-arm/new_vgic.h
 create mode 100644 xen/include/xen/list_sort.h

-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 01/39] xen/arm: gic: Read unconditionally the source from the LRs
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
@ 2018-03-21 16:31 ` Andre Przywara
  2018-03-21 16:31 ` [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version Andre Przywara
                   ` (37 subsequent siblings)
  38 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:31 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

From: Julien Grall <julien.grall@arm.com>

Commit 5cb00d1 "ARM: GIC: extend LR read/write functions to cover EOI
and source" extended gic_lr to cover the source. The new field was only
set for SGIs interrupt in the read function. However, the write function
is writing the field unconditionally for virtual interrupt.

This means that if the caller was combining the 2 functions (e.g to
update the LR), the source need to be set to 0 by the caller.
Unfortunately, gic_update_one_lr is not zeroing the structure before
reading the LRs. This will lead to trigger the assert randomly.

Instead of zeroing the structure in gic_update_one_lr, make sure that
the source is written unconditionally on read. This is also simplifying
the code to avoid an if statement in the read path.

Lastly, properly update the comments in write_lr that was mistakenly
speaking about the read lr path.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 xen/arch/arm/gic-v2.c | 15 ++++++++-------
 xen/arch/arm/gic-v3.c | 13 ++++++++-----
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index 7dfe6fc68d..aa0fc6c1a1 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -480,11 +480,12 @@ static void gicv2_read_lr(int lr, struct gic_lr *lr_reg)
     else
     {
         lr_reg->virt.eoi = (lrv & GICH_V2_LR_MAINTENANCE_IRQ);
-        if ( lr_reg->virq < NR_GIC_SGI )
-        {
-            lr_reg->virt.source = (lrv >> GICH_V2_LR_CPUID_SHIFT)
-                & GICH_V2_LR_CPUID_MASK;
-        }
+        /*
+         * This is only valid for SGI, but it does not matter to always
+         * read it as it should be 0 by default.
+         */
+        lr_reg->virt.source = (lrv >> GICH_V2_LR_CPUID_SHIFT)
+            & GICH_V2_LR_CPUID_MASK;
     }
 }
 
@@ -512,8 +513,8 @@ static void gicv2_write_lr(int lr, const struct gic_lr *lr_reg)
         if ( lr_reg->virt.eoi )
             lrv |= GICH_V2_LR_MAINTENANCE_IRQ;
         /*
-         * This is only valid for SGI, but it does not matter to always
-         * read it as it should be 0 by default.
+         * Source is only valid for SGIs, the caller should make sure
+         * the field virt.source is always 0 for non-SGI.
          */
         ASSERT(!lr_reg->virt.source || lr_reg->virq < NR_GIC_SGI);
         lrv |= (uint32_t)lr_reg->virt.source << GICH_V2_LR_CPUID_SHIFT;
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 392cf91b58..cb41844af2 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -1018,10 +1018,13 @@ static void gicv3_read_lr(int lr, struct gic_lr *lr_reg)
     else
     {
         lr_reg->virt.eoi = (lrv & ICH_LR_MAINTENANCE_IRQ);
-        /* Source only exists for SGI and in GICv2 compatible mode */
-        if ( lr_reg->virq < NR_GIC_SGI &&
-             current->domain->arch.vgic.version == GIC_V2 )
+        /* Source only exists in GICv2 compatible mode */
+        if ( current->domain->arch.vgic.version == GIC_V2 )
         {
+            /*
+             * This is only valid for SGI, but it does not matter to always
+             * read it as it should be 0 by default.
+             */
             lr_reg->virt.source = (lrv >> ICH_LR_CPUID_SHIFT)
                 & ICH_LR_CPUID_MASK;
         }
@@ -1056,8 +1059,8 @@ static void gicv3_write_lr(int lr_reg, const struct gic_lr *lr)
         if ( vgic_version == GIC_V2 )
         {
             /*
-             * This is only valid for SGI, but it does not matter to always
-             * read it as it should be 0 by default.
+             * Source is only valid for SGIs, the caller should make
+             * sure the field virt.source is always 0 for non-SGI.
              */
             ASSERT(!lr->virt.source || lr->virq < NR_GIC_SGI);
             lrv |= (uint64_t)lr->virt.source << ICH_LR_CPUID_SHIFT;
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
  2018-03-21 16:31 ` [PATCH v3 01/39] xen/arm: gic: Read unconditionally the source from the LRs Andre Przywara
@ 2018-03-21 16:31 ` Andre Przywara
  2018-03-22  1:39   ` Julien Grall
  2018-03-26 20:08   ` Stefano Stabellini
  2018-03-21 16:31 ` [PATCH v3 03/39] ARM: GIC: Allow tweaking the active and pending state of an IRQ Andre Przywara
                   ` (36 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:31 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The enum gic_version at the moment just contains GIC_V2 and GIC_V3,
where GIC_V2 happens to map to 0. So without having initialised a
variable of that type, we will read back GIC_V2 (when allocated with zeroing
the memory).
To prevent ambiguities and to give an explicitly uninitialised state, add
a new first member: GIC_INVALID. Also make it obvious that this has a
"0" encoding.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
 xen/include/asm-arm/gic.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 565b0875ca..3079387e06 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -227,6 +227,7 @@ struct gic_lr {
 };
 
 enum gic_version {
+    GIC_INVALID = 0,    /* the default until explicitly set up */
     GIC_V2,
     GIC_V3,
 };
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 03/39] ARM: GIC: Allow tweaking the active and pending state of an IRQ
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
  2018-03-21 16:31 ` [PATCH v3 01/39] xen/arm: gic: Read unconditionally the source from the LRs Andre Przywara
  2018-03-21 16:31 ` [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version Andre Przywara
@ 2018-03-21 16:31 ` Andre Przywara
  2018-03-22  1:51   ` Julien Grall
  2018-03-21 16:32 ` [PATCH v3 04/39] ARM: GIC: Allow reading pending state of a hardware IRQ Andre Przywara
                   ` (35 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:31 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

When playing around with hardware mapped, level triggered virtual IRQs,
there is the need to explicitly set the active or pending state of an
interrupt at some point.
To prepare the GIC for that, we introduce a set_active_state() and a
set_pending_state() function to let the VGIC manipulate the state of
an associated hardware IRQ.
This takes care of properly setting the _IRQ_INPROGRESS bit.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- rework setting _IRQ_INPROGRESS bit:
  - no change when changing active state
  - unconditional set/clear on changing pending state
- drop introduction of gicv[23]_peek_irq() (only needed in the next patch now)

Changelog v1 ... v2:
- properly set _IRQ_INPROGRESS bit
- add gicv[23]_peek_irq() (pulled in from later patch)
- move wrappers functions into gic.h

 xen/arch/arm/gic-v2.c     | 36 ++++++++++++++++++++++++++++++++++++
 xen/arch/arm/gic-v3.c     | 32 ++++++++++++++++++++++++++++++++
 xen/include/asm-arm/gic.h | 24 ++++++++++++++++++++++++
 3 files changed, 92 insertions(+)

diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index aa0fc6c1a1..d1f1578c05 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -243,6 +243,40 @@ static void gicv2_poke_irq(struct irq_desc *irqd, uint32_t offset)
     writel_gicd(1U << (irqd->irq % 32), offset + (irqd->irq / 32) * 4);
 }
 
+static void gicv2_set_active_state(struct irq_desc *irqd, bool active)
+{
+    ASSERT(spin_is_locked(&irqd->lock));
+
+    if ( active )
+    {
+        if ( test_bit(_IRQ_GUEST, &irqd->status) )
+            set_bit(_IRQ_INPROGRESS, &irqd->status);
+        gicv2_poke_irq(irqd, GICD_ISACTIVER);
+    }
+    else
+    {
+        if ( test_bit(_IRQ_GUEST, &irqd->status) )
+            clear_bit(_IRQ_INPROGRESS, &irqd->status);
+        gicv2_poke_irq(irqd, GICD_ICACTIVER);
+    }
+}
+
+static void gicv2_set_pending_state(struct irq_desc *irqd, bool pending)
+{
+    ASSERT(spin_is_locked(&irqd->lock));
+
+    if ( pending )
+    {
+        /* The _IRQ_INPROGRESS bit will be set when the interrupt fires. */
+        gicv2_poke_irq(irqd, GICD_ISPENDR);
+    }
+    else
+    {
+        /* The _IRQ_INPROGRESS remains unchanged. */
+        gicv2_poke_irq(irqd, GICD_ICPENDR);
+    }
+}
+
 static void gicv2_set_irq_type(struct irq_desc *desc, unsigned int type)
 {
     uint32_t cfg, actual, edgebit;
@@ -1278,6 +1312,8 @@ const static struct gic_hw_operations gicv2_ops = {
     .eoi_irq             = gicv2_eoi_irq,
     .deactivate_irq      = gicv2_dir_irq,
     .read_irq            = gicv2_read_irq,
+    .set_active_state    = gicv2_set_active_state,
+    .set_pending_state   = gicv2_set_pending_state,
     .set_irq_type        = gicv2_set_irq_type,
     .set_irq_priority    = gicv2_set_irq_priority,
     .send_SGI            = gicv2_send_SGI,
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index cb41844af2..f244d51661 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -477,6 +477,36 @@ static unsigned int gicv3_read_irq(void)
     return irq;
 }
 
+static void gicv3_set_active_state(struct irq_desc *irqd, bool active)
+{
+    ASSERT(spin_is_locked(&irqd->lock));
+
+    if ( active )
+    {
+        if ( test_bit(_IRQ_GUEST, &irqd->status) )
+            set_bit(_IRQ_INPROGRESS, &irqd->status);
+        gicv3_poke_irq(irqd, GICD_ISACTIVER, false);
+    }
+    else
+    {
+        if ( test_bit(_IRQ_GUEST, &irqd->status) )
+            clear_bit(_IRQ_INPROGRESS, &irqd->status);
+        gicv3_poke_irq(irqd, GICD_ICACTIVER, false);
+    }
+}
+
+static void gicv3_set_pending_state(struct irq_desc *irqd, bool pending)
+{
+    ASSERT(spin_is_locked(&irqd->lock));
+
+    if ( pending )
+        /* The _IRQ_INPROGRESS bit will be set when the interrupt fires. */
+        gicv3_poke_irq(irqd, GICD_ISPENDR, false);
+    else
+        /* The _IRQ_INPROGRESS bit will remain unchanged. */
+        gicv3_poke_irq(irqd, GICD_ICPENDR, false);
+}
+
 static inline uint64_t gicv3_mpidr_to_affinity(int cpu)
 {
      uint64_t mpidr = cpu_logical_map(cpu);
@@ -1769,6 +1799,8 @@ static const struct gic_hw_operations gicv3_ops = {
     .eoi_irq             = gicv3_eoi_irq,
     .deactivate_irq      = gicv3_dir_irq,
     .read_irq            = gicv3_read_irq,
+    .set_active_state    = gicv3_set_active_state,
+    .set_pending_state   = gicv3_set_pending_state,
     .set_irq_type        = gicv3_set_irq_type,
     .set_irq_priority    = gicv3_set_irq_priority,
     .send_SGI            = gicv3_send_sgi,
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 3079387e06..2aca243ac3 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -345,6 +345,10 @@ struct gic_hw_operations {
     void (*deactivate_irq)(struct irq_desc *irqd);
     /* Read IRQ id and Ack */
     unsigned int (*read_irq)(void);
+    /* Force the active state of an IRQ by accessing the distributor */
+    void (*set_active_state)(struct irq_desc *irqd, bool state);
+    /* Force the pending state of an IRQ by accessing the distributor */
+    void (*set_pending_state)(struct irq_desc *irqd, bool state);
     /* Set IRQ type */
     void (*set_irq_type)(struct irq_desc *desc, unsigned int type);
     /* Set IRQ priority */
@@ -393,6 +397,26 @@ static inline unsigned int gic_get_nr_lrs(void)
     return gic_hw_ops->info->nr_lrs;
 }
 
+/*
+ * Set the active state of an IRQ. This should be used with care, as this
+ * directly forces the active bit, without considering the GIC state machine.
+ * For private IRQs this only works for those of the current CPU.
+ */
+static inline void gic_set_active_state(struct irq_desc *irqd, bool state)
+{
+    gic_hw_ops->set_active_state(irqd, state);
+}
+
+/*
+ * Set the pending state of an IRQ. This should be used with care, as this
+ * directly forces the pending bit, without considering the GIC state machine.
+ * For private IRQs this only works for those of the current CPU.
+ */
+static inline void gic_set_pending_state(struct irq_desc *irqd, bool state)
+{
+    gic_hw_ops->set_pending_state(irqd, state);
+}
+
 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,
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 04/39] ARM: GIC: Allow reading pending state of a hardware IRQ
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (2 preceding siblings ...)
  2018-03-21 16:31 ` [PATCH v3 03/39] ARM: GIC: Allow tweaking the active and pending state of an IRQ Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-26 20:08   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly Andre Przywara
                   ` (34 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

To synchronize level triggered interrupts which are mapped into a guest,
we need to update the virtual line level at certain points in time.
For a hardware mapped interrupt the GIC is the only place where we can
easily access this information.
Implement a gic_hw_operations member to return the pending state of a
particular interrupt. Due to hardware limitations this only works for
private interrupts of the current CPU, so there is no CPU field in the
prototype.
This adds gicv2/3_peek_irq() helper functions, to read a bit in a bitmap
spread over several MMIO registers.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
Changelog v2 ... v3:
- introduce gicv[23]_peek_irq() (moved from patch before)

 xen/arch/arm/gic-v2.c     | 15 +++++++++++++++
 xen/arch/arm/gic-v3.c     | 19 +++++++++++++++++++
 xen/include/asm-arm/gic.h | 11 +++++++++++
 3 files changed, 45 insertions(+)

diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
index d1f1578c05..b440a45e8e 100644
--- a/xen/arch/arm/gic-v2.c
+++ b/xen/arch/arm/gic-v2.c
@@ -243,6 +243,15 @@ static void gicv2_poke_irq(struct irq_desc *irqd, uint32_t offset)
     writel_gicd(1U << (irqd->irq % 32), offset + (irqd->irq / 32) * 4);
 }
 
+static bool gicv2_peek_irq(struct irq_desc *irqd, uint32_t offset)
+{
+    uint32_t reg;
+
+    reg = readl_gicd(offset + (irqd->irq / 32) * 4) & (1U << (irqd->irq % 32));
+
+    return reg;
+}
+
 static void gicv2_set_active_state(struct irq_desc *irqd, bool active)
 {
     ASSERT(spin_is_locked(&irqd->lock));
@@ -580,6 +589,11 @@ static unsigned int gicv2_read_apr(int apr_reg)
    return readl_gich(GICH_APR);
 }
 
+static bool gicv2_read_pending_state(struct irq_desc *irqd)
+{
+    return gicv2_peek_irq(irqd, GICD_ISPENDR);
+}
+
 static void gicv2_irq_enable(struct irq_desc *desc)
 {
     unsigned long flags;
@@ -1325,6 +1339,7 @@ const static struct gic_hw_operations gicv2_ops = {
     .write_lr            = gicv2_write_lr,
     .read_vmcr_priority  = gicv2_read_vmcr_priority,
     .read_apr            = gicv2_read_apr,
+    .read_pending_state  = gicv2_read_pending_state,
     .make_hwdom_dt_node  = gicv2_make_hwdom_dt_node,
     .make_hwdom_madt     = gicv2_make_hwdom_madt,
     .get_hwdom_extra_madt_size = gicv2_get_hwdom_extra_madt_size,
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index f244d51661..5c9a783968 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -444,6 +444,19 @@ static void gicv3_poke_irq(struct irq_desc *irqd, u32 offset, bool wait_for_rwp)
         gicv3_wait_for_rwp(irqd->irq);
 }
 
+static bool gicv3_peek_irq(struct irq_desc *irqd, u32 offset)
+{
+    void __iomem *base;
+    unsigned int irq = irqd->irq;
+
+    if ( irq >= NR_GIC_LOCAL_IRQS)
+        base = GICD + (irq / 32) * 4;
+    else
+        base = GICD_RDIST_SGI_BASE;
+
+    return !!(readl(base + offset) & (1U << (irq % 32)));
+}
+
 static void gicv3_unmask_irq(struct irq_desc *irqd)
 {
     gicv3_poke_irq(irqd, GICD_ISENABLER, false);
@@ -1144,6 +1157,11 @@ static unsigned int gicv3_read_apr(int apr_reg)
     }
 }
 
+static bool gicv3_read_pending_state(struct irq_desc *irqd)
+{
+    return gicv3_peek_irq(irqd, GICD_ISPENDR);
+}
+
 static void gicv3_irq_enable(struct irq_desc *desc)
 {
     unsigned long flags;
@@ -1812,6 +1830,7 @@ static const struct gic_hw_operations gicv3_ops = {
     .write_lr            = gicv3_write_lr,
     .read_vmcr_priority  = gicv3_read_vmcr_priority,
     .read_apr            = gicv3_read_apr,
+    .read_pending_state  = gicv3_read_pending_state,
     .secondary_init      = gicv3_secondary_cpu_init,
     .make_hwdom_dt_node  = gicv3_make_hwdom_dt_node,
     .make_hwdom_madt     = gicv3_make_hwdom_madt,
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 2aca243ac3..58b910fe6a 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -373,6 +373,8 @@ struct gic_hw_operations {
     unsigned int (*read_vmcr_priority)(void);
     /* Read APRn register */
     unsigned int (*read_apr)(int apr_reg);
+    /* Query the pending state of an interrupt at the distributor level. */
+    bool (*read_pending_state)(struct irq_desc *irqd);
     /* Secondary CPU init */
     int (*secondary_init)(void);
     /* Create GIC node for the hardware domain */
@@ -417,6 +419,15 @@ static inline void gic_set_pending_state(struct irq_desc *irqd, bool state)
     gic_hw_ops->set_pending_state(irqd, state);
 }
 
+/*
+ * Read the pending state of an interrupt from the distributor.
+ * For private IRQs this only works for those of the current CPU.
+ */
+static inline bool gic_read_pending_state(struct irq_desc *irqd)
+{
+    return gic_hw_ops->read_pending_state(irqd);
+}
+
 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,
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (3 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 04/39] ARM: GIC: Allow reading pending state of a hardware IRQ Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  1:58   ` Julien Grall
  2018-03-26 20:28   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 06/39] ARM: evtchn: " Andre Przywara
                   ` (33 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The ARM Generic Timer uses a level-sensitive interrupt semantic. We
easily catch when the line goes high, as this triggers the hardware IRQ.
However we also have to keep track of when the line lowers, as the
emulation depends on it: Upon entering the guest, the new VGIC will
*clear* the virtual interrupt line, so it needs to re-sample the actual
state after returning from the guest.
So we have to sync the state of the interrupt condition at certain
points to catch when the line goes low and we can remove the vtimer vIRQ
from the vGIC (and the LR).
The VGIC in Xen so far only implemented edge triggered vIRQs, really, so
we need to add new functionality to re-sample the interrupt state.
Do this only when the new VGIC is in use.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- move vtimer_sync() from time.c into vtimer.c
- rename function to vtimer_update_irqs()
- refactor functionality into new static function, to ...
- handle physical timer as well
- extending comments

Changelog v1 ... v2:
- restrict to new VGIC
- add TODO: comment

 xen/arch/arm/traps.c         | 11 ++++++++++
 xen/arch/arm/vtimer.c        | 49 ++++++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/vtimer.h |  1 +
 3 files changed, 61 insertions(+)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 7411bff7a7..2638446693 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -2024,6 +2024,17 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
         if ( current->arch.hcr_el2 & HCR_VA )
             current->arch.hcr_el2 = READ_SYSREG(HCR_EL2);
 
+#ifdef CONFIG_NEW_VGIC
+        /*
+         * We need to update the state of our emulated devices using level
+         * triggered interrupts before syncing back the VGIC state.
+         *
+         * TODO: Investigate whether this is necessary to do on every
+         * trap and how it can be optimised.
+         */
+        vtimer_update_irqs(current);
+#endif
+
         vgic_sync_from_lrs(current);
     }
 }
diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c
index 8164f6c7f1..c99dd237d1 100644
--- a/xen/arch/arm/vtimer.c
+++ b/xen/arch/arm/vtimer.c
@@ -334,6 +334,55 @@ bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr)
     }
 }
 
+static void vtimer_update_irq(struct vcpu *v, struct vtimer *vtimer,
+                              uint32_t vtimer_ctl)
+{
+    bool level;
+
+    /* Filter for the three bits that determine the status of the timer */
+    vtimer_ctl &= (CNTx_CTL_ENABLE | CNTx_CTL_PENDING | CNTx_CTL_MASK);
+
+    /* The level is high if the timer is pending and enabled, but not masked. */
+    level = (vtimer_ctl == (CNTx_CTL_ENABLE | CNTx_CTL_PENDING));
+
+    /*
+     * This is mostly here to *lower* the virtual interrupt line if the timer
+     * is no longer pending.
+     * We would have injected an IRQ already via SOFTIRQ when the timer expired.
+     * Doing it here again is basically a NOP if the line was already high.
+     */
+    vgic_inject_irq(v->domain, v, vtimer->irq, level);
+}
+
+/**
+ * vtimer_update_irqs() - update the virtual timers' IRQ lines after a guest run
+ * @vcpu: The VCPU to sync the timer state
+ *
+ * After returning from a guest, update the state of the timers' virtual
+ * interrupt lines, to model the level triggered interrupts correctly.
+ * If the guest has handled a timer interrupt, the virtual interrupt line
+ * needs to be lowered explicitly. vgic_inject_irq() takes care of that.
+ */
+void vtimer_update_irqs(struct vcpu *v)
+{
+    /*
+     * For the virtual timer we read the current state from the hardware.
+     * Technically we should keep the CNTx_CTL_MASK bit here, to catch if
+     * the timer interrupt is masked. However Xen *always* masks the timer
+     * upon entering the hypervisor, leaving it up to the guest to un-mask it.
+     * So we would always read a "low" level, despite the condition being
+     * actually "high".  Ignoring the mask bit solves this (for now).
+     *
+     * TODO: The proper fix for this is to make vtimer vIRQ hardware mapped,
+     * but this requires reworking the arch timer to implement this.
+     */
+    vtimer_update_irq(v, &v->arch.virt_timer,
+                      READ_SYSREG32(CNTV_CTL_EL0) & ~CNTx_CTL_MASK);
+
+    /* For the physical timer we rely on our emulated state. */
+    vtimer_update_irq(v, &v->arch.phys_timer, v->arch.phys_timer.ctl);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/asm-arm/vtimer.h b/xen/include/asm-arm/vtimer.h
index 5aaddc6f63..91d88b377f 100644
--- a/xen/include/asm-arm/vtimer.h
+++ b/xen/include/asm-arm/vtimer.h
@@ -27,6 +27,7 @@ extern bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr);
 extern int virt_timer_save(struct vcpu *v);
 extern int virt_timer_restore(struct vcpu *v);
 extern void vcpu_timer_destroy(struct vcpu *v);
+void vtimer_update_irqs(struct vcpu *v);
 
 #endif
 
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (4 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  2:08   ` Julien Grall
                     ` (2 more replies)
  2018-03-21 16:32 ` [PATCH v3 07/39] ARM: vPL011: Use the VGIC's level triggered IRQs handling if available Andre Przywara
                   ` (32 subsequent siblings)
  38 siblings, 3 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The event channel IRQ has level triggered semantics, however the current
VGIC treats everything as edge triggered.
To correctly process those IRQs, we have to lower the (virtual) IRQ line
at some point in time, depending on whether ther interrupt condition
still prevails.
Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
line match its status, and call this function upon every hypervisor
entry.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/domain.c       | 7 +++++++
 xen/arch/arm/traps.c        | 1 +
 xen/include/asm-arm/event.h | 1 +
 3 files changed, 9 insertions(+)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index ff97f2bc76..9688e62f78 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
     vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
 }
 
+void vcpu_update_evtchn_irq(struct vcpu *v)
+{
+    bool pending = vcpu_info(v, evtchn_upcall_pending);
+
+    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
+}
+
 /* The ARM spec declares that even if local irqs are masked in
  * the CPSR register, an irq should wake up a cpu from WFI anyway.
  * For this reason we need to check for irqs that need delivery,
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 2638446693..5c18e918b0 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
          * trap and how it can be optimised.
          */
         vtimer_update_irqs(current);
+        vcpu_update_evtchn_irq(current);
 #endif
 
         vgic_sync_from_lrs(current);
diff --git a/xen/include/asm-arm/event.h b/xen/include/asm-arm/event.h
index c7a415ef57..2f51864043 100644
--- a/xen/include/asm-arm/event.h
+++ b/xen/include/asm-arm/event.h
@@ -6,6 +6,7 @@
 
 void vcpu_kick(struct vcpu *v);
 void vcpu_mark_events_pending(struct vcpu *v);
+void vcpu_update_evtchn_irq(struct vcpu *v);
 void vcpu_block_unless_event_pending(struct vcpu *v);
 
 static inline int vcpu_event_delivery_is_enabled(struct vcpu *v)
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 07/39] ARM: vPL011: Use the VGIC's level triggered IRQs handling if available
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (5 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 06/39] ARM: evtchn: " Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-26 20:20   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 08/39] ARM: new VGIC: Add data structure definitions Andre Przywara
                   ` (31 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The emulated ARM SBSA UART is using level triggered IRQ semantics,
however the current VGIC can only handle edge triggered IRQs, really.
Disable the existing workaround for this problem in case we have the
new VGIC in place, which can properly handle level triggered IRQs.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vpl011.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
index 5dcf4bec18..a281eabd7e 100644
--- a/xen/arch/arm/vpl011.c
+++ b/xen/arch/arm/vpl011.c
@@ -54,6 +54,7 @@ static void vpl011_update_interrupt_status(struct domain *d)
      */
     ASSERT(spin_is_locked(&vpl011->lock));
 
+#ifndef CONFIG_NEW_VGIC
     /*
      * TODO: PL011 interrupts are level triggered which means
      * that interrupt needs to be set/clear instead of being
@@ -71,6 +72,9 @@ static void vpl011_update_interrupt_status(struct domain *d)
         vgic_inject_irq(d, NULL, GUEST_VPL011_SPI, true);
 
     vpl011->shadow_uartmis = uartmis;
+#else
+    vgic_inject_irq(d, NULL, GUEST_VPL011_SPI, uartmis);
+#endif
 }
 
 static uint8_t vpl011_read_data(struct domain *d)
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 08/39] ARM: new VGIC: Add data structure definitions
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (6 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 07/39] ARM: vPL011: Use the VGIC's level triggered IRQs handling if available Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-26 20:41   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 09/39] ARM: new VGIC: Add accessor to new struct vgic_irq instance Andre Przywara
                   ` (30 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Add a new header file for the new and improved GIC implementation.
The big change is that we now have a struct vgic_irq per IRQ instead
of spreading all the information over various bitmaps in the ranks.

We include this new header conditionally from within the old header
file for the time being to avoid touching all the users.

This is based on Linux commit b18b57787f5e, written by Christoffer Dall.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/include/asm-arm/new_vgic.h | 198 +++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-arm/vgic.h     |   6 ++
 2 files changed, 204 insertions(+)
 create mode 100644 xen/include/asm-arm/new_vgic.h

diff --git a/xen/include/asm-arm/new_vgic.h b/xen/include/asm-arm/new_vgic.h
new file mode 100644
index 0000000000..97d622bff6
--- /dev/null
+++ b/xen/include/asm-arm/new_vgic.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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_NEW_VGIC_H
+#define __ASM_ARM_NEW_VGIC_H
+
+#include <asm/atomic.h>
+#include <asm/mmio.h>
+#include <xen/list.h>
+#include <xen/mm.h>
+#include <xen/spinlock.h>
+
+#define VGIC_V3_MAX_CPUS        255
+#define VGIC_V2_MAX_CPUS        8
+#define VGIC_NR_SGIS            16
+#define VGIC_NR_PPIS            16
+#define VGIC_NR_PRIVATE_IRQS    (VGIC_NR_SGIS + VGIC_NR_PPIS)
+#define VGIC_MAX_PRIVATE        (VGIC_NR_PRIVATE_IRQS - 1)
+#define VGIC_MAX_SPI            1019
+#define VGIC_MAX_RESERVED       1023
+#define VGIC_MIN_LPI            8192
+
+#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
+#define irq_is_spi(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
+                         (irq) <= VGIC_MAX_SPI)
+
+enum vgic_type {
+    VGIC_V2,        /* Good ol' GICv2 */
+    VGIC_V3,        /* New fancy GICv3 */
+};
+
+#define VGIC_V2_MAX_LRS         (1 << 6)
+#define VGIC_V3_MAX_LRS         16
+#define VGIC_V3_LR_INDEX(lr)    (VGIC_V3_MAX_LRS - 1 - lr)
+
+#define VGIC_CONFIG_EDGE        false
+#define VGIC_CONFIG_LEVEL       true
+
+struct vgic_irq {
+    struct list_head ap_list;
+
+    struct vcpu *vcpu;          /*
+                                 * SGIs and PPIs: The VCPU
+                                 * SPIs and LPIs: The VCPU whose ap_list
+                                 * this is queued on.
+                                 */
+
+    struct vcpu *target_vcpu;   /*
+                                 * The VCPU that this interrupt should
+                                 * be sent to, as a result of the
+                                 * targets reg (v2) or the affinity reg (v3).
+                                 */
+
+    spinlock_t irq_lock;        /* Protects the content of the struct */
+    uint32_t intid;             /* Guest visible INTID */
+    atomic_t refcount;          /* Used for LPIs */
+    uint32_t hwintid;           /* HW INTID number */
+    union
+    {
+        struct {
+            uint8_t targets;    /* GICv2 target VCPUs mask */
+            uint8_t source;     /* GICv2 SGIs only */
+        };
+        uint32_t mpidr;         /* GICv3 target VCPU */
+    };
+    uint8_t priority;
+    bool line_level:1;          /* Level only */
+    bool pending_latch:1;       /*
+                                 * The pending latch state used to
+                                 * calculate the pending state for both
+                                 * level and edge triggered IRQs.
+                                 */
+    bool active:1;              /* not used for LPIs */
+    bool enabled:1;
+    bool hw:1;                  /* Tied to HW IRQ */
+    bool config:1;              /* Level or edge */
+    struct list_head lpi_list;  /* Used to link all LPIs together */
+};
+
+enum iodev_type {
+    IODEV_DIST,
+    IODEV_REDIST,
+};
+
+struct vgic_io_device {
+    gfn_t base_fn;
+    struct vcpu *redist_vcpu;
+    const struct vgic_register_region *regions;
+    enum iodev_type iodev_type;
+    unsigned int nr_regions;
+};
+
+struct vgic_dist {
+    bool                ready;
+    bool                initialized;
+
+    /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
+    uint32_t            version;
+
+    /* Do injected MSIs require an additional device ID? */
+    bool                msis_require_devid;
+
+    unsigned int        nr_spis;
+
+    /* base addresses in guest physical address space: */
+    paddr_t             vgic_dist_base;     /* distributor */
+    union
+    {
+        /* either a GICv2 CPU interface */
+        paddr_t         vgic_cpu_base;
+        /* or a number of GICv3 redistributor regions */
+        struct
+        {
+            paddr_t     vgic_redist_base;
+            paddr_t     vgic_redist_free_offset;
+        };
+    };
+
+    /* distributor enabled */
+    bool                enabled;
+
+    struct vgic_irq     *spis;
+    unsigned long       *allocated_irqs; /* bitmap of IRQs allocated */
+
+    struct vgic_io_device   dist_iodev;
+
+    bool                has_its;
+
+    /*
+     * Contains the attributes and gpa of the LPI configuration table.
+     * Since we report GICR_TYPER.CommonLPIAff as 0b00, we can share
+     * one address across all redistributors.
+     * GICv3 spec: 6.1.2 "LPI Configuration tables"
+     */
+    uint64_t            propbaser;
+
+    /* Protects the lpi_list and the count value below. */
+    spinlock_t          lpi_list_lock;
+    struct list_head    lpi_list_head;
+    unsigned int        lpi_list_count;
+};
+
+struct vgic_cpu {
+    struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
+
+    struct list_head ap_list_head;
+    spinlock_t ap_list_lock;    /* Protects the ap_list */
+
+    unsigned int used_lrs;
+
+    /*
+     * List of IRQs that this VCPU should consider because they are either
+     * Active or Pending (hence the name; AP list), or because they recently
+     * were one of the two and need to be migrated off this list to another
+     * VCPU.
+     */
+
+    /*
+     * Members below are used with GICv3 emulation only and represent
+     * parts of the redistributor.
+     */
+    struct vgic_io_device   rd_iodev;
+    struct vgic_io_device   sgi_iodev;
+
+    /* Contains the attributes and gpa of the LPI pending tables. */
+    uint64_t pendbaser;
+
+    bool lpis_enabled;
+
+    /* Cache guest priority bits */
+    uint32_t num_pri_bits;
+
+    /* Cache guest interrupt ID bits */
+    uint32_t num_id_bits;
+};
+
+#endif /* __ASM_ARM_NEW_VGIC_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/vgic.h b/xen/include/asm-arm/vgic.h
index 0787ba9549..2a58ea30fe 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -18,6 +18,10 @@
 #ifndef __ASM_ARM_VGIC_H__
 #define __ASM_ARM_VGIC_H__
 
+#ifdef CONFIG_NEW_VGIC
+#include <asm/new_vgic.h>
+#else
+
 #include <xen/bitops.h>
 #include <xen/radix-tree.h>
 #include <xen/rbtree.h>
@@ -299,6 +303,8 @@ extern bool vgic_to_sgi(struct vcpu *v, register_t sgir,
                         const struct sgi_target *target);
 extern bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq);
 
+#endif /* !CONFIG_NEW_VGIC */
+
 /*** Common VGIC functions used by Xen arch code ****/
 
 /*
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 09/39] ARM: new VGIC: Add accessor to new struct vgic_irq instance
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (7 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 08/39] ARM: new VGIC: Add data structure definitions Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  2:11   ` Julien Grall
  2018-03-21 16:32 ` [PATCH v3 10/39] ARM: new VGIC: Implement virtual IRQ injection Andre Przywara
                   ` (29 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The new VGIC implementation centers around a struct vgic_irq instance
per virtual IRQ.
Provide a function to retrieve the right instance for a given IRQ
number and (in case of private interrupts) the right VCPU.
This also includes the corresponding put function, which does nothing
for private interrupts and SPIs, but handles the ref-counting for LPIs.

This is based on Linux commit 64a959d66e47, written by Christoffer Dall.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- extend comments to note preliminary nature of vgic_get_lpi()

Changelog v1 ... v2:
- reorder header file inclusion

 xen/arch/arm/vgic/vgic.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.h |  41 +++++++++++++++
 2 files changed, 175 insertions(+)
 create mode 100644 xen/arch/arm/vgic/vgic.c
 create mode 100644 xen/arch/arm/vgic/vgic.h

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
new file mode 100644
index 0000000000..a818e382b1
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
+ *
+ * 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/sched.h>
+#include <asm/bug.h>
+#include <asm/new_vgic.h>
+
+#include "vgic.h"
+
+/*
+ * Iterate over the VM's list of mapped LPIs to find the one with a
+ * matching interrupt ID and return a reference to the IRQ structure.
+ *
+ * TODO: This is more documentation of how it should be done. A list is
+ * not a good data structure for Dom0's LPIs, it merely serves as an
+ * example here how to properly do the locking, allocation and refcounting.
+ * So lpi_list_head should be replaced with something more appropriate.
+ */
+static struct vgic_irq *vgic_get_lpi(struct domain *d, u32 intid)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+    struct vgic_irq *irq = NULL;
+
+    spin_lock(&dist->lpi_list_lock);
+
+    list_for_each_entry( irq, &dist->lpi_list_head, lpi_list )
+    {
+        if ( irq->intid != intid )
+            continue;
+
+        /*
+         * This increases the refcount, the caller is expected to
+         * call vgic_put_irq() later once it's finished with the IRQ.
+         */
+        vgic_get_irq_kref(irq);
+        goto out_unlock;
+    }
+    irq = NULL;
+
+out_unlock:
+    spin_unlock(&dist->lpi_list_lock);
+
+    return irq;
+}
+
+/**
+ * vgic_get_irq() - obtain a reference to a virtual IRQ
+ * @d:        The domain the virtual IRQ belongs to.
+ * @vcpu:     For private IRQs (SGIs, PPIs) the virtual CPU this IRQ
+ *            is associated with. Will be ignored for SPIs and LPIs.
+ * @intid:    The virtual IRQ number.
+ *
+ * This looks up the virtual interrupt ID to get the corresponding
+ * struct vgic_irq. It also increases the refcount, so any caller is expected
+ * to call vgic_put_irq() once it's finished with this IRQ.
+ *
+ * Return: The pointer to the requested struct vgic_irq.
+ */
+struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
+                              u32 intid)
+{
+    /* SGIs and PPIs */
+    if ( intid <= VGIC_MAX_PRIVATE )
+        return &vcpu->arch.vgic.private_irqs[intid];
+
+    /* SPIs */
+    if ( intid <= VGIC_MAX_SPI )
+        return &d->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
+
+    /* LPIs */
+    if ( intid >= VGIC_MIN_LPI )
+        return vgic_get_lpi(d, intid);
+
+    ASSERT_UNREACHABLE();
+
+    return NULL;
+}
+
+/**
+ * vgic_put_irq() - drop the reference to a virtual IRQ
+ * @d:        The domain the virtual IRQ belongs to.
+ * @irq:      The pointer to struct vgic_irq, as obtained from vgic_get_irq().
+ *
+ * This drops the reference to a virtual IRQ. It decreases the refcount
+ * of the pointer, so dynamic IRQs can be freed when no longer needed.
+ * This should always be called after a vgic_get_irq(), though the reference
+ * can be deliberately held for longer periods, if needed.
+ *
+ * TODO: A linked list is not a good data structure for LPIs in Dom0.
+ * Replace this with proper data structure once we get proper LPI support.
+ */
+void vgic_put_irq(struct domain *d, struct vgic_irq *irq)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+
+    if ( irq->intid < VGIC_MIN_LPI )
+        return;
+
+    spin_lock(&dist->lpi_list_lock);
+    if ( !atomic_dec_and_test(&irq->refcount) )
+    {
+        spin_unlock(&dist->lpi_list_lock);
+        return;
+    };
+
+    list_del(&irq->lpi_list);
+    dist->lpi_list_count--;
+    spin_unlock(&dist->lpi_list_lock);
+
+    xfree(irq);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
new file mode 100644
index 0000000000..a3befd386b
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
+ *
+ * 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 __XEN_ARM_VGIC_VGIC_H__
+#define __XEN_ARM_VGIC_VGIC_H__
+
+struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
+                              u32 intid);
+void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
+
+static inline void vgic_get_irq_kref(struct vgic_irq *irq)
+{
+    if ( irq->intid < VGIC_MIN_LPI )
+        return;
+
+    atomic_inc(&irq->refcount);
+}
+
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 10/39] ARM: new VGIC: Implement virtual IRQ injection
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (8 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 09/39] ARM: new VGIC: Add accessor to new struct vgic_irq instance Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-26 21:01   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 11/39] Add list_sort() routine from Linux Andre Przywara
                   ` (28 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Provide a vgic_queue_irq_unlock() function which decides whether a
given IRQ needs to be queued to a VCPU's ap_list.
This should be called whenever an IRQ becomes pending or enabled,
either as a result of a hardware IRQ injection, from devices emulated by
Xen (like the architected timer) or from MMIO accesses to the distributor
emulation.
Also provides the necessary functions to allow to inject an IRQ to a guest.
Since this is the first code that starts using our locking mechanism,
we add some (hopefully) clear documentation of our locking strategy and
requirements along with this patch.

This is based on Linux commit 81eeb95ddbab, written by Christoffer Dall.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.h |  10 +++
 2 files changed, 236 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index a818e382b1..f7dfd01c1d 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -17,10 +17,36 @@
 
 #include <xen/sched.h>
 #include <asm/bug.h>
+#include <asm/event.h>
 #include <asm/new_vgic.h>
 
 #include "vgic.h"
 
+/*
+ * Locking order is always:
+ *   vgic->lock
+ *     vgic_cpu->ap_list_lock
+ *       vgic->lpi_list_lock
+ *         desc->lock
+ *           vgic_irq->irq_lock
+ *
+ * If you need to take multiple locks, always take the upper lock first,
+ * then the lower ones, e.g. first take the ap_list_lock, then the irq_lock.
+ * If you are already holding a lock and need to take a higher one, you
+ * have to drop the lower ranking lock first and re-acquire it after having
+ * taken the upper one.
+ *
+ * When taking more than one ap_list_lock at the same time, always take the
+ * lowest numbered VCPU's ap_list_lock first, so:
+ *   vcpuX->vcpu_id < vcpuY->vcpu_id:
+ *     spin_lock(vcpuX->arch.vgic.ap_list_lock);
+ *     spin_lock(vcpuY->arch.vgic.ap_list_lock);
+ *
+ * Since the VGIC must support injecting virtual interrupts from ISRs, we have
+ * to use the spin_lock_irqsave/spin_unlock_irqrestore versions of outer
+ * spinlocks for any lock that may be taken while injecting an interrupt.
+ */
+
 /*
  * Iterate over the VM's list of mapped LPIs to find the one with a
  * matching interrupt ID and return a reference to the IRQ structure.
@@ -124,6 +150,206 @@ void vgic_put_irq(struct domain *d, struct vgic_irq *irq)
     xfree(irq);
 }
 
+/**
+ * vgic_target_oracle() - compute the target vcpu for an irq
+ * @irq:    The irq to route. Must be already locked.
+ *
+ * Based on the current state of the interrupt (enabled, pending,
+ * active, vcpu and target_vcpu), compute the next vcpu this should be
+ * given to. Return NULL if this shouldn't be injected at all.
+ *
+ * Requires the IRQ lock to be held.
+ *
+ * Returns: The pointer to the virtual CPU this interrupt should be injected
+ *          to. Will be NULL if this IRQ does not need to be injected.
+ */
+static struct vcpu *vgic_target_oracle(struct vgic_irq *irq)
+{
+    ASSERT(spin_is_locked(&irq->irq_lock));
+
+    /* If the interrupt is active, it must stay on the current vcpu */
+    if ( irq->active )
+        return irq->vcpu ? : irq->target_vcpu;
+
+    /*
+     * If the IRQ is not active but enabled and pending, we should direct
+     * it to its configured target VCPU.
+     * If the distributor is disabled, pending interrupts shouldn't be
+     * forwarded.
+     */
+    if ( irq->enabled && irq_is_pending(irq) )
+    {
+        if ( unlikely(irq->target_vcpu &&
+                      !irq->target_vcpu->domain->arch.vgic.enabled) )
+            return NULL;
+
+        return irq->target_vcpu;
+    }
+
+    /*
+     * If neither active nor pending and enabled, then this IRQ should not
+     * be queued to any VCPU.
+     */
+    return NULL;
+}
+
+/*
+ * Only valid injection if changing level for level-triggered IRQs or for a
+ * rising edge.
+ */
+static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
+{
+    /* For edge interrupts we only care about a rising edge. */
+    if ( irq->config == VGIC_CONFIG_EDGE )
+        return level;
+
+    /* For level interrupts we have to act when the line level changes. */
+    return irq->line_level != level;
+}
+
+/**
+ * vgic_queue_irq_unlock() - Queue an IRQ to a VCPU, to be injected to a guest.
+ * @d:        The domain the virtual IRQ belongs to.
+ * @irq:      A pointer to the vgic_irq of the virtual IRQ, with the lock held.
+ * @flags:    The flags used when having grabbed the IRQ lock.
+ *
+ * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
+ * Do the queuing if necessary, taking the right locks in the right order.
+ *
+ * Needs to be entered with the IRQ lock already held, but will return
+ * with all locks dropped.
+ */
+void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
+                           unsigned long flags)
+{
+    struct vcpu *vcpu;
+
+    ASSERT(spin_is_locked(&irq->irq_lock));
+
+retry:
+    vcpu = vgic_target_oracle(irq);
+    if ( irq->vcpu || !vcpu )
+    {
+        /*
+         * If this IRQ is already on a VCPU's ap_list, then it
+         * cannot be moved or modified and there is no more work for
+         * us to do.
+         *
+         * Otherwise, if the irq is not pending and enabled, it does
+         * not need to be inserted into an ap_list and there is also
+         * no more work for us to do.
+         */
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+        /*
+         * We have to kick the VCPU here, because we could be
+         * queueing an edge-triggered interrupt for which we
+         * get no EOI maintenance interrupt. In that case,
+         * while the IRQ is already on the VCPU's AP list, the
+         * VCPU could have EOI'ed the original interrupt and
+         * won't see this one until it exits for some other
+         * reason.
+         */
+        if ( vcpu )
+            vcpu_kick(vcpu);
+
+        return;
+    }
+
+    /*
+     * We must unlock the irq lock to take the ap_list_lock where
+     * we are going to insert this new pending interrupt.
+     */
+    spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+    /* someone can do stuff here, which we re-check below */
+
+    spin_lock_irqsave(&vcpu->arch.vgic.ap_list_lock, flags);
+    spin_lock(&irq->irq_lock);
+
+    /*
+     * Did something change behind our backs?
+     *
+     * There are two cases:
+     * 1) The irq lost its pending state or was disabled behind our
+     *    backs and/or it was queued to another VCPU's ap_list.
+     * 2) Someone changed the affinity on this irq behind our
+     *    backs and we are now holding the wrong ap_list_lock.
+     *
+     * In both cases, drop the locks and retry.
+     */
+
+    if ( unlikely(irq->vcpu || vcpu != vgic_target_oracle(irq)) )
+    {
+        spin_unlock(&irq->irq_lock);
+        spin_unlock_irqrestore(&vcpu->arch.vgic.ap_list_lock, flags);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+        goto retry;
+    }
+
+    /*
+     * Grab a reference to the irq to reflect the fact that it is
+     * now in the ap_list.
+     */
+    vgic_get_irq_kref(irq);
+    list_add_tail(&irq->ap_list, &vcpu->arch.vgic.ap_list_head);
+    irq->vcpu = vcpu;
+
+    spin_unlock(&irq->irq_lock);
+    spin_unlock_irqrestore(&vcpu->arch.vgic.ap_list_lock, flags);
+
+    vcpu_kick(vcpu);
+
+    return;
+}
+
+/**
+ * vgic_inject_irq() - Inject an IRQ from a device to the vgic
+ * @d:       The domain pointer
+ * @vcpu:    The vCPU for private IRQs (PPIs, SGIs). Ignored for SPIs and LPIs.
+ * @intid:   The INTID to inject a new state to.
+ * @level:   Edge-triggered:  true:  to trigger the interrupt
+ *                            false: to ignore the call
+ *           Level-sensitive  true:  raise the input signal
+ *                            false: lower the input signal
+ *
+ * Injects an instance of the given virtual IRQ into a domain.
+ * The VGIC is not concerned with devices being active-LOW or active-HIGH for
+ * level-sensitive interrupts.  You can think of the level parameter as 1
+ * being HIGH and 0 being LOW and all devices being active-HIGH.
+ */
+void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,
+                     bool level)
+{
+    struct vgic_irq *irq;
+    unsigned long flags;
+
+    irq = vgic_get_irq(d, vcpu, intid);
+    if ( !irq )
+        return;
+
+    spin_lock_irqsave(&irq->irq_lock, flags);
+
+    if ( !vgic_validate_injection(irq, level) )
+    {
+        /* Nothing to see here, move along... */
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+        vgic_put_irq(d, irq);
+        return;
+    }
+
+    if ( irq->config == VGIC_CONFIG_LEVEL )
+        irq->line_level = level;
+    else
+        irq->pending_latch = true;
+
+    vgic_queue_irq_unlock(d, irq, flags);
+    vgic_put_irq(d, irq);
+
+    return;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index a3befd386b..f9e2eeb2d6 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -17,9 +17,19 @@
 #ifndef __XEN_ARM_VGIC_VGIC_H__
 #define __XEN_ARM_VGIC_VGIC_H__
 
+static inline bool irq_is_pending(struct vgic_irq *irq)
+{
+    if ( irq->config == VGIC_CONFIG_EDGE )
+        return irq->pending_latch;
+    else
+        return irq->pending_latch || irq->line_level;
+}
+
 struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
                               u32 intid);
 void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
+void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
+                           unsigned long flags);
 
 static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 {
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 11/39] Add list_sort() routine from Linux
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (9 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 10/39] ARM: new VGIC: Implement virtual IRQ injection Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-21 17:01   ` Jan Beulich
  2018-03-22  2:14   ` Julien Grall
  2018-03-21 16:32 ` [PATCH v3 12/39] ARM: new VGIC: Add IRQ sorting Andre Przywara
                   ` (27 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: Wei Liu, George Dunlap, Andrew Cooper, Ian Jackson,
	Andre Przywara, Tim Deegan, Jan Beulich, xen-devel

This pulls in Linux' list_sort.c, which is a merge sort implementation
for linked lists. Apart from adding a full featured license header and
adjusting the #include file, nothing has been changed in this code.
Define a promptless Kconfig which configurations can select when they
need this code and add it to the Makefile.

This is from Linux' lib/list_sort.c, as of commit e327fd7c8667
("lib: add module support to linked list sorting tests").

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- introduce promptless Kconfig
- add Makefile line
- note Linux commit ID

 xen/common/Kconfig          |   3 +
 xen/common/Makefile         |   1 +
 xen/common/list_sort.c      | 157 ++++++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/list_sort.h |  11 ++++
 4 files changed, 172 insertions(+)
 create mode 100644 xen/common/list_sort.c
 create mode 100644 xen/include/xen/list_sort.h

diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 68abf7a5e5..986f6c4149 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -44,6 +44,9 @@ config HAS_GDBSX
 config HAS_IOPORTS
 	bool
 
+config NEEDS_LIST_SORT
+        bool
+
 config HAS_BUILD_ID
 	string
 	option env="XEN_HAS_BUILD_ID"
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 3a349f478b..24d4752ccc 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -19,6 +19,7 @@ obj-y += keyhandler.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_KEXEC) += kimage.o
 obj-y += lib.o
+obj-$(CONFIG_NEEDS_LIST_SORT) += list_sort.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o livepatch_elf.o
 obj-y += lzo.o
 obj-$(CONFIG_HAS_MEM_ACCESS) += mem_access.o
diff --git a/xen/common/list_sort.c b/xen/common/list_sort.c
new file mode 100644
index 0000000000..af2b2f6519
--- /dev/null
+++ b/xen/common/list_sort.c
@@ -0,0 +1,157 @@
+/*
+ * list_sort.c: merge sort implementation for linked lists
+ * Copied from the Linux kernel (lib/list_sort.c)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/lib.h>
+#include <xen/list.h>
+
+#define MAX_LIST_LENGTH_BITS 20
+
+/*
+ * Returns a list organized in an intermediate format suited
+ * to chaining of merge() calls: null-terminated, no reserved or
+ * sentinel head node, "prev" links not maintained.
+ */
+static struct list_head *merge(void *priv,
+				int (*cmp)(void *priv, struct list_head *a,
+					struct list_head *b),
+				struct list_head *a, struct list_head *b)
+{
+	struct list_head head, *tail = &head;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(priv, a, b) <= 0) {
+			tail->next = a;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a?:b;
+	return head.next;
+}
+
+/*
+ * Combine final list merge with restoration of standard doubly-linked
+ * list structure.  This approach duplicates code from merge(), but
+ * runs faster than the tidier alternatives of either a separate final
+ * prev-link restoration pass, or maintaining the prev links
+ * throughout.
+ */
+static void merge_and_restore_back_links(void *priv,
+				int (*cmp)(void *priv, struct list_head *a,
+					struct list_head *b),
+				struct list_head *head,
+				struct list_head *a, struct list_head *b)
+{
+	struct list_head *tail = head;
+	u8 count = 0;
+
+	while (a && b) {
+		/* if equal, take 'a' -- important for sort stability */
+		if ((*cmp)(priv, a, b) <= 0) {
+			tail->next = a;
+			a->prev = tail;
+			a = a->next;
+		} else {
+			tail->next = b;
+			b->prev = tail;
+			b = b->next;
+		}
+		tail = tail->next;
+	}
+	tail->next = a ? : b;
+
+	do {
+		/*
+		 * In worst cases this loop may run many iterations.
+		 * Continue callbacks to the client even though no
+		 * element comparison is needed, so the client's cmp()
+		 * routine can invoke cond_resched() periodically.
+		 */
+		if (unlikely(!(++count)))
+			(*cmp)(priv, tail->next, tail->next);
+
+		tail->next->prev = tail;
+		tail = tail->next;
+	} while (tail->next);
+
+	tail->next = head;
+	head->prev = tail;
+}
+
+/**
+ * list_sort - sort a list
+ * @priv: private data, opaque to list_sort(), passed to @cmp
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function implements "merge sort", which has O(nlog(n))
+ * complexity.
+ *
+ * The comparison function @cmp must return a negative value if @a
+ * should sort before @b, and a positive value if @a should sort after
+ * @b. If @a and @b are equivalent, and their original relative
+ * ordering is to be preserved, @cmp must return 0.
+ */
+void list_sort(void *priv, struct list_head *head,
+		int (*cmp)(void *priv, struct list_head *a,
+			struct list_head *b))
+{
+	struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+						-- last slot is a sentinel */
+	int lev;  /* index into part[] */
+	int max_lev = 0;
+	struct list_head *list;
+
+	if (list_empty(head))
+		return;
+
+	memset(part, 0, sizeof(part));
+
+	head->prev->next = NULL;
+	list = head->next;
+
+	while (list) {
+		struct list_head *cur = list;
+		list = list->next;
+		cur->next = NULL;
+
+		for (lev = 0; part[lev]; lev++) {
+			cur = merge(priv, cmp, part[lev], cur);
+			part[lev] = NULL;
+		}
+		if (lev > max_lev) {
+			if (unlikely(lev >= ARRAY_SIZE(part)-1)) {
+				dprintk(XENLOG_DEBUG,
+					"list too long for efficiency\n");
+				lev--;
+			}
+			max_lev = lev;
+		}
+		part[lev] = cur;
+	}
+
+	for (lev = 0; lev < max_lev; lev++)
+		if (part[lev])
+			list = merge(priv, cmp, part[lev], list);
+
+	merge_and_restore_back_links(priv, cmp, head, part[max_lev], list);
+}
+EXPORT_SYMBOL(list_sort);
diff --git a/xen/include/xen/list_sort.h b/xen/include/xen/list_sort.h
new file mode 100644
index 0000000000..13ce0a55ec
--- /dev/null
+++ b/xen/include/xen/list_sort.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_LIST_SORT_H
+#define _LINUX_LIST_SORT_H
+
+#include <xen/types.h>
+
+struct list_head;
+
+void list_sort(void *priv, struct list_head *head,
+	       int (*cmp)(void *priv, struct list_head *a,
+			  struct list_head *b));
+#endif
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 12/39] ARM: new VGIC: Add IRQ sorting
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (10 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 11/39] Add list_sort() routine from Linux Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-26 21:16   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework Andre Przywara
                   ` (26 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Adds the sorting function to cover the case where you have more IRQs
to consider than you have LRs. We consider their priorities.
This uses the new sort_list() implementation imported from Linux.

This is based on Linux commit 8e4447457965, written by Christoffer Dall.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index f7dfd01c1d..ee0de8d2e0 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -15,6 +15,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <xen/list_sort.h>
 #include <xen/sched.h>
 #include <asm/bug.h>
 #include <asm/event.h>
@@ -193,6 +194,64 @@ static struct vcpu *vgic_target_oracle(struct vgic_irq *irq)
     return NULL;
 }
 
+/*
+ * The order of items in the ap_lists defines how we'll pack things in LRs as
+ * well, the first items in the list being the first things populated in the
+ * LRs.
+ *
+ * A hard rule is that active interrupts can never be pushed out of the LRs
+ * (and therefore take priority) since we cannot reliably trap on deactivation
+ * of IRQs and therefore they have to be present in the LRs.
+ *
+ * Otherwise things should be sorted by the priority field and the GIC
+ * hardware support will take care of preemption of priority groups etc.
+ *
+ * Return negative if "a" sorts before "b", 0 to preserve order, and positive
+ * to sort "b" before "a".
+ */
+static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+    struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
+    struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
+    bool penda, pendb;
+    int ret;
+
+    spin_lock(&irqa->irq_lock);
+    spin_lock(&irqb->irq_lock);
+
+    if ( irqa->active || irqb->active )
+    {
+        ret = (int)irqb->active - (int)irqa->active;
+        goto out;
+    }
+
+    penda = irqa->enabled && irq_is_pending(irqa);
+    pendb = irqb->enabled && irq_is_pending(irqb);
+
+    if ( !penda || !pendb )
+    {
+        ret = (int)pendb - (int)penda;
+        goto out;
+    }
+
+    /* Both pending and enabled, sort by priority */
+    ret = irqa->priority - irqb->priority;
+out:
+    spin_unlock(&irqb->irq_lock);
+    spin_unlock(&irqa->irq_lock);
+    return ret;
+}
+
+/* Must be called with the ap_list_lock held */
+static void vgic_sort_ap_list(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+
+    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
+
+    list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
+}
+
 /*
  * Only valid injection if changing level for level-triggered IRQs or for a
  * rising edge.
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (11 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 12/39] ARM: new VGIC: Add IRQ sorting Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  2:16   ` Julien Grall
  2018-03-26 21:30   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend Andre Przywara
                   ` (25 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Implement the framework for syncing IRQs between our emulation and the
list registers, which represent the guest's view of IRQs.
This is done in vgic_sync_from_lrs() and vgic_sync_to_lrs(), which
get called on guest entry and exit, respectively.
The code talking to the actual GICv2/v3 hardware is added in the
following patches.

This is based on Linux commit 0919e84c0fc1, written by Marc Zyngier.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- replace "true" instead of "1" for the boolean parameter

Changelog v1 ... v2:
- make functions void
- do underflow setting directly (no v2/v3 indirection)
- fix multiple SGIs injections (as the late Linux bugfix)

 xen/arch/arm/vgic/vgic.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.h |   2 +
 2 files changed, 234 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index ee0de8d2e0..52e1669888 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -409,6 +409,238 @@ void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,
     return;
 }
 
+/**
+ * vgic_prune_ap_list() - Remove non-relevant interrupts from the ap_list
+ *
+ * @vcpu:       The VCPU of which the ap_list should be pruned.
+ *
+ * Go over the list of interrupts on a VCPU's ap_list, and prune those that
+ * we won't have to consider in the near future.
+ * This removes interrupts that have been successfully handled by the guest,
+ * or that have otherwise became obsolete (not pending anymore).
+ * Also this moves interrupts between VCPUs, if their affinity has changed.
+ */
+static void vgic_prune_ap_list(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+    struct vgic_irq *irq, *tmp;
+    unsigned long flags;
+
+retry:
+    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
+
+    list_for_each_entry_safe( irq, tmp, &vgic_cpu->ap_list_head, ap_list )
+    {
+        struct vcpu *target_vcpu, *vcpuA, *vcpuB;
+
+        spin_lock(&irq->irq_lock);
+
+        BUG_ON(vcpu != irq->vcpu);
+
+        target_vcpu = vgic_target_oracle(irq);
+
+        if ( !target_vcpu )
+        {
+            /*
+             * We don't need to process this interrupt any
+             * further, move it off the list.
+             */
+            list_del(&irq->ap_list);
+            irq->vcpu = NULL;
+            spin_unlock(&irq->irq_lock);
+
+            /*
+             * This vgic_put_irq call matches the
+             * vgic_get_irq_kref in vgic_queue_irq_unlock,
+             * where we added the LPI to the ap_list. As
+             * we remove the irq from the list, we drop
+             * also drop the refcount.
+             */
+            vgic_put_irq(vcpu->domain, irq);
+            continue;
+        }
+
+        if ( target_vcpu == vcpu )
+        {
+            /* We're on the right CPU */
+            spin_unlock(&irq->irq_lock);
+            continue;
+        }
+
+        /* This interrupt looks like it has to be migrated. */
+
+        spin_unlock(&irq->irq_lock);
+        spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
+
+        /*
+         * Ensure locking order by always locking the smallest
+         * ID first.
+         */
+        if ( vcpu->vcpu_id < target_vcpu->vcpu_id )
+        {
+            vcpuA = vcpu;
+            vcpuB = target_vcpu;
+        }
+        else
+        {
+            vcpuA = target_vcpu;
+            vcpuB = vcpu;
+        }
+
+        spin_lock_irqsave(&vcpuA->arch.vgic.ap_list_lock, flags);
+        spin_lock(&vcpuB->arch.vgic.ap_list_lock);
+        spin_lock(&irq->irq_lock);
+
+        /*
+         * If the affinity has been preserved, move the
+         * interrupt around. Otherwise, it means things have
+         * changed while the interrupt was unlocked, and we
+         * need to replay this.
+         *
+         * In all cases, we cannot trust the list not to have
+         * changed, so we restart from the beginning.
+         */
+        if ( target_vcpu == vgic_target_oracle(irq) )
+        {
+            struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic;
+
+            list_del(&irq->ap_list);
+            irq->vcpu = target_vcpu;
+            list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
+        }
+
+        spin_unlock(&irq->irq_lock);
+        spin_unlock(&vcpuB->arch.vgic.ap_list_lock);
+        spin_unlock_irqrestore(&vcpuA->arch.vgic.ap_list_lock, flags);
+        goto retry;
+    }
+
+    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
+}
+
+static void vgic_fold_lr_state(struct vcpu *vcpu)
+{
+}
+
+/* Requires the irq_lock to be held. */
+static void vgic_populate_lr(struct vcpu *vcpu,
+                             struct vgic_irq *irq, int lr)
+{
+    ASSERT(spin_is_locked(&irq->irq_lock));
+}
+
+static void vgic_set_underflow(struct vcpu *vcpu)
+{
+    ASSERT(vcpu == current);
+
+    gic_hw_ops->update_hcr_status(GICH_HCR_UIE, true);
+}
+
+/* Requires the ap_list_lock to be held. */
+static int compute_ap_list_depth(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+    struct vgic_irq *irq;
+    int count = 0;
+
+    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
+
+    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
+    {
+        spin_lock(&irq->irq_lock);
+        /* GICv2 SGIs can count for more than one... */
+        if ( vgic_irq_is_sgi(irq->intid) && irq->source )
+            count += hweight8(irq->source);
+        else
+            count++;
+        spin_unlock(&irq->irq_lock);
+    }
+    return count;
+}
+
+/* Requires the VCPU's ap_list_lock to be held. */
+static void vgic_flush_lr_state(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+    struct vgic_irq *irq;
+    int count = 0;
+
+    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
+
+    if ( compute_ap_list_depth(vcpu) > gic_get_nr_lrs() )
+        vgic_sort_ap_list(vcpu);
+
+    list_for_each_entry( irq, &vgic_cpu->ap_list_head, ap_list )
+    {
+        spin_lock(&irq->irq_lock);
+
+        if ( likely(vgic_target_oracle(irq) == vcpu) )
+            vgic_populate_lr(vcpu, irq, count++);
+
+        spin_unlock(&irq->irq_lock);
+
+        if ( count == gic_get_nr_lrs() )
+        {
+            if ( !list_is_last(&irq->ap_list, &vgic_cpu->ap_list_head) )
+                vgic_set_underflow(vcpu);
+            break;
+        }
+    }
+
+    vcpu->arch.vgic.used_lrs = count;
+}
+
+/**
+ * vgic_sync_from_lrs() - Update VGIC state from hardware after a guest's run.
+ * @vcpu: the VCPU for which to transfer from the LRs to the IRQ list.
+ *
+ * Sync back the hardware VGIC state after the guest has run, into our
+ * VGIC emulation structures, It reads the LRs and updates the respective
+ * struct vgic_irq, taking level/edge into account.
+ * This is the high level function which takes care of the conditions,
+ * also bails out early if there were no interrupts queued.
+ * Was: kvm_vgic_sync_hwstate()
+ */
+void vgic_sync_from_lrs(struct vcpu *vcpu)
+{
+    /* An empty ap_list_head implies used_lrs == 0 */
+    if ( list_empty(&vcpu->arch.vgic.ap_list_head) )
+        return;
+
+    vgic_fold_lr_state(vcpu);
+
+    vgic_prune_ap_list(vcpu);
+}
+
+/**
+ * vgic_sync_to_lrs() - flush emulation state into the hardware on guest entry
+ *
+ * Before we enter a guest, we have to translate the virtual GIC state of a
+ * VCPU into the GIC virtualization hardware registers, namely the LRs.
+ * This is the high level function which takes care about the conditions
+ * and the locking, also bails out early if there are no interrupts queued.
+ * Was: kvm_vgic_flush_hwstate()
+ */
+void vgic_sync_to_lrs(void)
+{
+    /*
+     * If there are no virtual interrupts active or pending for this
+     * VCPU, then there is no work to do and we can bail out without
+     * taking any lock.  There is a potential race with someone injecting
+     * interrupts to the VCPU, but it is a benign race as the VCPU will
+     * either observe the new interrupt before or after doing this check,
+     * and introducing additional synchronization mechanism doesn't change
+     * this.
+     */
+    if ( list_empty(&current->arch.vgic.ap_list_head) )
+        return;
+
+    ASSERT(!local_irq_is_enabled());
+
+    spin_lock(&current->arch.vgic.ap_list_lock);
+    vgic_flush_lr_state(current);
+    spin_unlock(&current->arch.vgic.ap_list_lock);
+}
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index f9e2eeb2d6..f530cfa078 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -17,6 +17,8 @@
 #ifndef __XEN_ARM_VGIC_VGIC_H__
 #define __XEN_ARM_VGIC_VGIC_H__
 
+#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
+
 static inline bool irq_is_pending(struct vgic_irq *irq)
 {
     if ( irq->config == VGIC_CONFIG_EDGE )
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (12 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  3:48   ` Julien Grall
  2018-03-21 16:32 ` [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq Andre Przywara
                   ` (24 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Processing maintenance interrupts and accessing the list registers
are dependent on the host's GIC version.
Introduce vgic-v2.c to contain GICv2 specific functions.
Implement the GICv2 specific code for syncing the emulation state
into the VGIC registers.
This also adds the hook to let Xen setup the host GIC addresses.

This is based on Linux commit 140b086dd197, written by Marc Zyngier.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- remove no longer needed asm/io.h header
- replace 0/1 with false/true for bool's
- clear _IRQ_INPROGRESS bit when retiring hardware mapped IRQ
- fix indentation and w/s issues

Changelog v1 ... v2:
- remove v2 specific underflow function (now generic)
- re-add Linux code to properly handle acked level IRQs

 xen/arch/arm/vgic/vgic-v2.c | 239 ++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.c    |   6 ++
 xen/arch/arm/vgic/vgic.h    |   9 ++
 3 files changed, 254 insertions(+)
 create mode 100644 xen/arch/arm/vgic/vgic-v2.c

diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c
new file mode 100644
index 0000000000..8ab0cfe81d
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic-v2.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
+ *
+ * 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 <asm/new_vgic.h>
+#include <asm/bug.h>
+#include <asm/gic.h>
+#include <xen/sched.h>
+#include <xen/sizes.h>
+
+#include "vgic.h"
+
+static struct {
+    bool enabled;
+    paddr_t dbase;          /* Distributor interface address */
+    paddr_t cbase;          /* CPU interface address & size */
+    paddr_t csize;
+    paddr_t vbase;          /* Virtual CPU interface address */
+
+    /* Offset to add to get an 8kB contiguous region if GIC is aliased */
+    uint32_t aliased_offset;
+} gic_v2_hw_data;
+
+void vgic_v2_setup_hw(paddr_t dbase, paddr_t cbase, paddr_t csize,
+                      paddr_t vbase, uint32_t aliased_offset)
+{
+    gic_v2_hw_data.enabled = true;
+    gic_v2_hw_data.dbase = dbase;
+    gic_v2_hw_data.cbase = cbase;
+    gic_v2_hw_data.csize = csize;
+    gic_v2_hw_data.vbase = vbase;
+    gic_v2_hw_data.aliased_offset = aliased_offset;
+}
+
+/*
+ * transfer the content of the LRs back into the corresponding ap_list:
+ * - active bit is transferred as is
+ * - pending bit is
+ *   - transferred as is in case of edge sensitive IRQs
+ *   - set to the line-level (resample time) for level sensitive IRQs
+ */
+void vgic_v2_fold_lr_state(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+    unsigned int used_lrs = vcpu->arch.vgic.used_lrs;
+    unsigned long flags;
+    unsigned int lr;
+
+    if ( !used_lrs )    /* No LRs used, so nothing to sync back here. */
+        return;
+
+    gic_hw_ops->update_hcr_status(GICH_HCR_UIE, false);
+
+    for ( lr = 0; lr < used_lrs; lr++ )
+    {
+        struct gic_lr lr_val;
+        uint32_t intid;
+        struct vgic_irq *irq;
+
+        gic_hw_ops->read_lr(lr, &lr_val);
+
+        /*
+         * TODO: Possible optimization to avoid reading LRs:
+         * Read the ELRSR to find out which of our LRs have been cleared
+         * by the guest. We just need to know the IRQ number for those, which
+         * we could save in an array when populating the LRs.
+         * This trades one MMIO access (ELRSR) for possibly more than one (LRs),
+         * but requires some more code to save the IRQ number and to handle
+         * those finished IRQs according to the algorithm below.
+         * We need some numbers to justify this: chances are that we don't
+         * have many LRs in use most of the time, so we might not save much.
+         */
+        gic_hw_ops->clear_lr(lr);
+
+        intid = lr_val.virq;
+        irq = vgic_get_irq(vcpu->domain, vcpu, intid);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        /*
+         * If a hardware mapped IRQ has been handled for good, we need to
+         * clear the _IRQ_INPROGRESS bit to allow handling of new IRQs.
+         */
+        if ( irq->hw && !lr_val.active && !lr_val.pending )
+        {
+            struct irq_desc *irqd = irq_to_desc(irq->hwintid);
+
+            clear_bit(_IRQ_INPROGRESS, &irqd->status);
+        }
+
+        /* Always preserve the active bit */
+        irq->active = lr_val.active;
+
+        /* Edge is the only case where we preserve the pending bit */
+        if ( irq->config == VGIC_CONFIG_EDGE && lr_val.pending )
+        {
+            irq->pending_latch = true;
+
+            if ( vgic_irq_is_sgi(intid) )
+                irq->source |= (1U << lr_val.virt.source);
+        }
+
+        /* Clear soft pending state when level irqs have been acked. */
+        if ( irq->config == VGIC_CONFIG_LEVEL && !lr_val.pending )
+            irq->pending_latch = false;
+
+        /*
+         * Level-triggered mapped IRQs are special because we only
+         * observe rising edges as input to the VGIC.
+         *
+         * If the guest never acked the interrupt we have to sample
+         * the physical line and set the line level, because the
+         * device state could have changed or we simply need to
+         * process the still pending interrupt later.
+         *
+         * If this causes us to lower the level, we have to also clear
+         * the physical active state, since we will otherwise never be
+         * told when the interrupt becomes asserted again.
+         */
+        if ( vgic_irq_is_mapped_level(irq) && lr_val.pending )
+        {
+            struct irq_desc *irqd;
+
+            ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
+
+            irqd = irq_to_desc(irq->hwintid);
+            irq->line_level = gic_read_pending_state(irqd);
+
+            if ( !irq->line_level )
+                gic_set_active_state(irqd, false);
+        }
+
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    gic_hw_ops->update_hcr_status(GICH_HCR_EN, false);
+    vgic_cpu->used_lrs = 0;
+}
+
+/**
+ * vgic_v2_populate_lr() - Populates an LR with the state of a given IRQ.
+ * @vcpu: The VCPU which the given @irq belongs to.
+ * @irq:  The IRQ to convert into an LR. The irq_lock must be held already.
+ * @lr:   The LR number to transfer the state into.
+ *
+ * This moves a virtual IRQ, represented by its vgic_irq, into a list register.
+ * Apart from translating the logical state into the LR bitfields, it also
+ * changes some state in the vgic_irq.
+ * For an edge sensitive IRQ the pending state is cleared in struct vgic_irq,
+ * for a level sensitive IRQ the pending state value is unchanged, as it is
+ * dictated directly by the input line level.
+ *
+ * If @irq describes an SGI with multiple sources, we choose the
+ * lowest-numbered source VCPU and clear that bit in the source bitmap.
+ *
+ * The irq_lock must be held by the caller.
+ */
+void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+    struct gic_lr lr_val = {0};
+
+    lr_val.virq = irq->intid;
+
+    if ( irq_is_pending(irq) )
+    {
+        lr_val.pending = true;
+
+        if ( irq->config == VGIC_CONFIG_EDGE )
+            irq->pending_latch = false;
+
+        if ( vgic_irq_is_sgi(irq->intid) )
+        {
+            u32 src = ffs(irq->source);
+
+            BUG_ON(!src);
+            lr_val.virt.source = (src - 1);
+            irq->source &= ~(1 << (src - 1));
+            if ( irq->source )
+                irq->pending_latch = true;
+        }
+    }
+
+    lr_val.active = irq->active;
+
+    if ( irq->hw )
+    {
+        lr_val.hw_status = true;
+        lr_val.hw.pirq = irq->hwintid;
+        /*
+         * Never set pending+active on a HW interrupt, as the
+         * pending state is kept at the physical distributor
+         * level.
+         */
+        if ( irq->active && irq_is_pending(irq) )
+            lr_val.pending = false;
+    }
+    else
+    {
+        if ( irq->config == VGIC_CONFIG_LEVEL )
+            lr_val.virt.eoi = true;
+    }
+
+    /*
+     * Level-triggered mapped IRQs are special because we only observe
+     * rising edges as input to the VGIC.  We therefore lower the line
+     * level here, so that we can take new virtual IRQs.  See
+     * vgic_v2_fold_lr_state for more info.
+     */
+    if ( vgic_irq_is_mapped_level(irq) && lr_val.pending )
+        irq->line_level = false;
+
+    /* The GICv2 LR only holds five bits of priority. */
+    lr_val.priority = irq->priority >> 3;
+
+    gic_hw_ops->write_lr(lr, &lr_val);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 52e1669888..2fa595f4f7 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -520,6 +520,7 @@ retry:
 
 static void vgic_fold_lr_state(struct vcpu *vcpu)
 {
+    vgic_v2_fold_lr_state(vcpu);
 }
 
 /* Requires the irq_lock to be held. */
@@ -527,6 +528,8 @@ static void vgic_populate_lr(struct vcpu *vcpu,
                              struct vgic_irq *irq, int lr)
 {
     ASSERT(spin_is_locked(&irq->irq_lock));
+
+    vgic_v2_populate_lr(vcpu, irq, lr);
 }
 
 static void vgic_set_underflow(struct vcpu *vcpu)
@@ -640,7 +643,10 @@ void vgic_sync_to_lrs(void)
     spin_lock(&current->arch.vgic.ap_list_lock);
     vgic_flush_lr_state(current);
     spin_unlock(&current->arch.vgic.ap_list_lock);
+
+    gic_hw_ops->update_hcr_status(GICH_HCR_EN, 1);
 }
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index f530cfa078..41cc0c5b54 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -27,6 +27,11 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
         return irq->pending_latch || irq->line_level;
 }
 
+static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
+{
+    return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
+}
+
 struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
                               u32 intid);
 void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
@@ -41,6 +46,10 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
     atomic_inc(&irq->refcount);
 }
 
+void vgic_v2_fold_lr_state(struct vcpu *vcpu);
+void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
+void vgic_v2_set_underflow(struct vcpu *vcpu);
+
 #endif
 
 /*
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (13 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  3:52   ` Julien Grall
  2018-03-21 16:32 ` [PATCH v3 16/39] ARM: new VGIC: Add MMIO handling framework Andre Przywara
                   ` (23 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Tell Xen whether a particular VCPU has an IRQ that needs handling
in the guest. This is used to decide whether a VCPU is runnable or
if a hypercall should be preempted to let the guest handle the IRQ.

This is based on Linux commit 90eee56c5f90, written by Eric Auger.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- adjust vgic_vcpu_pending_irq() to return integers, not false/true

Changelog v1 ... v2:
- adjust to new vgic_vcpu_pending_irq() prototype, drop wrapper

 xen/arch/arm/vgic/vgic.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 2fa595f4f7..925cda4580 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -647,6 +647,43 @@ void vgic_sync_to_lrs(void)
     gic_hw_ops->update_hcr_status(GICH_HCR_EN, 1);
 }
 
+/**
+ * vgic_vcpu_pending_irq() - determine if interrupts need to be injected
+ * @vcpu: The vCPU on which to check for interrupts.
+ *
+ * Checks whether there is an interrupt on the given VCPU which needs
+ * handling in the guest. This requires at least one IRQ to be pending
+ * and enabled.
+ *
+ * Returns: 1 if the guest should run to handle interrupts, 0 otherwise.
+ */
+int vgic_vcpu_pending_irq(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+    struct vgic_irq *irq;
+    unsigned long flags;
+    int ret = 0;
+
+    if ( !vcpu->domain->arch.vgic.enabled )
+        return 0;
+
+    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
+
+    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
+    {
+        spin_lock(&irq->irq_lock);
+        ret = irq_is_pending(irq) && irq->enabled;
+        spin_unlock(&irq->irq_lock);
+
+        if ( ret )
+            break;
+    }
+
+    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
+
+    return ret;
+}
+
 /*
  * Local variables:
  * mode: C
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 16/39] ARM: new VGIC: Add MMIO handling framework
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (14 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 20:07   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 17/39] ARM: new VGIC: Add GICv2 " Andre Przywara
                   ` (22 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Add an MMIO handling framework to the VGIC emulation:
Each register is described by its offset, size (or number of bits per
IRQ, if applicable) and the read/write handler functions. We provide
initialization macros to describe each GIC register later easily.

Separate dispatch functions for read and write accesses are connected
to Xen's MMIO handling framework and binary-search for the responsible
register handler based on the offset address within the region.

The register handler prototype are courtesy of Christoffer Dall.

This is based on Linux commit 4493b1c4866a, written by Marc Zyngier.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio.c | 180 ++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h |  89 +++++++++++++++++++++
 2 files changed, 269 insertions(+)
 create mode 100644 xen/arch/arm/vgic/vgic-mmio.c
 create mode 100644 xen/arch/arm/vgic/vgic-mmio.h

diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
new file mode 100644
index 0000000000..866023a84d
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -0,0 +1,180 @@
+/*
+ * VGIC MMIO handling functions
+ * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
+ *
+ * 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.
+ */
+
+#include <xen/bitops.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <asm/new_vgic.h>
+#include <asm/byteorder.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+unsigned long vgic_mmio_read_raz(struct vcpu *vcpu,
+                                 paddr_t addr, unsigned int len)
+{
+    return 0;
+}
+
+unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
+                                 paddr_t addr, unsigned int len)
+{
+    return -1UL;
+}
+
+void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
+                        unsigned int len, unsigned long val)
+{
+    /* Ignore */
+}
+
+static int match_region(const void *key, const void *elt)
+{
+    const unsigned int offset = (unsigned long)key;
+    const struct vgic_register_region *region = elt;
+
+    if ( offset < region->reg_offset )
+        return -1;
+
+    if ( offset >= region->reg_offset + region->len )
+        return 1;
+
+    return 0;
+}
+
+static const struct vgic_register_region *
+vgic_find_mmio_region(const struct vgic_register_region *regions,
+                      int nr_regions, unsigned int offset)
+{
+    return bsearch((void *)(uintptr_t)offset, regions, nr_regions,
+                   sizeof(regions[0]), match_region);
+}
+
+static bool check_region(const struct domain *d,
+                         const struct vgic_register_region *region,
+                         paddr_t addr, int len)
+{
+    unsigned int flags, nr_irqs = d->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+
+    switch ( len )
+    {
+    case sizeof(uint8_t):
+        flags = VGIC_ACCESS_8bit;
+        break;
+    case sizeof(uint32_t):
+        flags = VGIC_ACCESS_32bit;
+        break;
+    case sizeof(uint64_t):
+        flags = VGIC_ACCESS_64bit;
+        break;
+    default:
+        return false;
+    }
+
+    if ( (region->access_flags & flags) && IS_ALIGNED(addr, len) )
+    {
+        if ( !region->bits_per_irq )
+            return true;
+
+        /* Do we access a non-allocated IRQ? */
+        return VGIC_ADDR_TO_INTID(addr, region->bits_per_irq) < nr_irqs;
+    }
+
+    return false;
+}
+
+static const struct vgic_register_region *
+vgic_get_mmio_region(struct vcpu *vcpu, struct vgic_io_device *iodev,
+                     paddr_t addr, unsigned int len)
+{
+    const struct vgic_register_region *region;
+
+    region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
+                                   addr - gfn_to_gaddr(iodev->base_fn));
+    if ( !region || !check_region(vcpu->domain, region, addr, len) )
+        return NULL;
+
+    return region;
+}
+
+static int dispatch_mmio_read(struct vcpu *vcpu, mmio_info_t *info,
+                              register_t *r, void *priv)
+{
+    struct vgic_io_device *iodev = priv;
+    const struct vgic_register_region *region;
+    unsigned long data = 0;
+    paddr_t addr = info->gpa;
+    int len = 1U << info->dabt.size;
+
+    region = vgic_get_mmio_region(vcpu, iodev, addr, len);
+    if ( !region )
+    {
+        memset(r, 0, len);
+        return 0;
+    }
+
+    switch (iodev->iodev_type)
+    {
+    case IODEV_DIST:
+        data = region->read(vcpu, addr, len);
+        break;
+    case IODEV_REDIST:
+        data = region->read(iodev->redist_vcpu, addr, len);
+        break;
+    }
+
+    memcpy(r, &data, len);
+
+    return 1;
+}
+
+static int dispatch_mmio_write(struct vcpu *vcpu, mmio_info_t *info,
+                               register_t r, void *priv)
+{
+    struct vgic_io_device *iodev = priv;
+    const struct vgic_register_region *region;
+    unsigned long data = r;
+    paddr_t addr = info->gpa;
+    int len = 1U << info->dabt.size;
+
+    region = vgic_get_mmio_region(vcpu, iodev, addr, len);
+    if ( !region )
+        return 0;
+
+    switch (iodev->iodev_type)
+    {
+    case IODEV_DIST:
+        region->write(vcpu, addr, len, data);
+        break;
+    case IODEV_REDIST:
+        region->write(iodev->redist_vcpu, addr, len, data);
+        break;
+    }
+
+    return 1;
+}
+
+struct mmio_handler_ops vgic_io_ops = {
+    .read = dispatch_mmio_read,
+    .write = dispatch_mmio_write,
+};
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
new file mode 100644
index 0000000000..bf062a27ca
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ *
+ * 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 __XEN_ARM_VGIC_VGIC_MMIO_H__
+#define __XEN_ARM_VGIC_VGIC_MMIO_H__
+
+struct vgic_register_region {
+    unsigned int reg_offset;
+    unsigned int len;
+    unsigned int bits_per_irq;
+    unsigned int access_flags;
+    unsigned long (*read)(struct vcpu *vcpu, paddr_t addr,
+                          unsigned int len);
+    void (*write)(struct vcpu *vcpu, paddr_t addr,
+                  unsigned int len, unsigned long val);
+};
+
+extern struct mmio_handler_ops vgic_io_ops;
+
+#define VGIC_ACCESS_8bit    1
+#define VGIC_ACCESS_32bit   2
+#define VGIC_ACCESS_64bit   4
+
+/*
+ * Generate a mask that covers the number of bytes required to address
+ * up to 1024 interrupts, each represented by <bits> bits. This assumes
+ * that <bits> is a power of two.
+ */
+#define VGIC_ADDR_IRQ_MASK(bits) (((bits) * 1024 / 8) - 1)
+
+/*
+ * (addr & mask) gives us the _byte_ offset for the INT ID.
+ * We multiply this by 8 the get the _bit_ offset, then divide this by
+ * the number of bits to learn the actual INT ID.
+ * But instead of a division (which requires a "long long div" implementation),
+ * we shift by the binary logarithm of <bits>.
+ * This assumes that <bits> is a power of two.
+ */
+#define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
+                                         8 >> ilog2(bits))
+
+/*
+ * Some VGIC registers store per-IRQ information, with a different number
+ * of bits per IRQ. For those registers this macro is used.
+ * The _WITH_LENGTH version instantiates registers with a fixed length
+ * and is mutually exclusive with the _PER_IRQ version.
+ */
+#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, rd, wr, bpi, acc)  \
+    {                                                           \
+        .reg_offset = off,                                      \
+        .bits_per_irq = bpi,                                    \
+        .len = bpi * 1024 / 8,                                  \
+        .access_flags = acc,                                    \
+        .read = rd,                                             \
+        .write = wr,                                            \
+    }
+
+#define REGISTER_DESC_WITH_LENGTH(off, rd, wr, length, acc)     \
+    {                                                           \
+        .reg_offset = off,                                      \
+        .bits_per_irq = 0,                                      \
+        .len = length,                                          \
+        .access_flags = acc,                                    \
+        .read = rd,                                             \
+        .write = wr,                                            \
+    }
+
+unsigned long vgic_mmio_read_raz(struct vcpu *vcpu,
+                                 paddr_t addr, unsigned int len);
+
+unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
+                                 paddr_t addr, unsigned int len);
+
+void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
+                        unsigned int len, unsigned long val);
+
+#endif
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 17/39] ARM: new VGIC: Add GICv2 MMIO handling framework
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (15 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 16/39] ARM: new VGIC: Add MMIO handling framework Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 20:28   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers Andre Przywara
                   ` (21 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
using the initializer macros provided by the VGIC MMIO framework.
Provide a function to register the GICv2 distributor registers to
the Xen MMIO framework.
The actual handler functions are still stubs in this patch.

This is based on Linux commit fb848db39661, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c | 83 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.c    | 25 ++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    |  2 +
 xen/arch/arm/vgic/vgic.h         |  2 +
 4 files changed, 112 insertions(+)
 create mode 100644 xen/arch/arm/vgic/vgic-mmio-v2.c

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
new file mode 100644
index 0000000000..6f10cf16ca
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -0,0 +1,83 @@
+/*
+ * VGICv2 MMIO handling functions
+ * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
+ *
+ * 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.
+ */
+
+#include <xen/bitops.h>
+#include <xen/sched.h>
+#include <xen/sizes.h>
+#include <asm/new_vgic.h>
+
+#include "vgic.h"
+#include "vgic-mmio.h"
+
+static const struct vgic_register_region vgic_v2_dist_registers[] = {
+    REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
+        vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICACTIVER,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 2,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
+        VGIC_ACCESS_32bit),
+    REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+    REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
+        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
+        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
+};
+
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
+{
+    dev->regions = vgic_v2_dist_registers;
+    dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
+
+    return SZ_4K;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
index 866023a84d..a03e8d88b9 100644
--- a/xen/arch/arm/vgic/vgic-mmio.c
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -170,6 +170,31 @@ struct mmio_handler_ops vgic_io_ops = {
     .write = dispatch_mmio_write,
 };
 
+int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
+                             enum vgic_type type)
+{
+    struct vgic_io_device *io_device = &d->arch.vgic.dist_iodev;
+    unsigned int len;
+
+    switch ( type )
+    {
+    case VGIC_V2:
+        len = vgic_v2_init_dist_iodev(io_device);
+        break;
+    default:
+        BUG();
+    }
+
+    io_device->base_fn = dist_base_fn;
+    io_device->iodev_type = IODEV_DIST;
+    io_device->redist_vcpu = NULL;
+
+    register_mmio_handler(d, &vgic_io_ops, gfn_to_gaddr(dist_base_fn), len,
+                          io_device);
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index bf062a27ca..c280668694 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -86,4 +86,6 @@ unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
 void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
                         unsigned int len, unsigned long val);
 
+unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
+
 #endif
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index 41cc0c5b54..7f221fd195 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -49,6 +49,8 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 void vgic_v2_fold_lr_state(struct vcpu *vcpu);
 void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct vcpu *vcpu);
+int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
+                             enum vgic_type);
 
 #endif
 
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (16 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 17/39] ARM: new VGIC: Add GICv2 " Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  7:33   ` Julien Grall
  2018-03-27 20:38   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers Andre Przywara
                   ` (20 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Those three registers are v2 emulation specific, so their implementation
lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
as their implementation is pretty simple.
We choose to piggy-back on the existing KVM identification registers,
but use a different variant (major revision).
When the guest enables the distributor, we kick all VCPUs to get
potentially pending interrupts serviced.

This is based on Linux commit 2b0cda878965, written by Marc Zyngier.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- fix misleading comment about PRODUCT_ID letter
- clarify on meaning of VARIANT_ID_XEN

Changelog v1 ... v2:
use new IIDR values (KVM product ID, Xen revision)
- add comment on handling GICD enablement
- use new vcpu_kick() function

 xen/arch/arm/vgic/vgic-mmio-v2.c | 63 +++++++++++++++++++++++++++++++++++++++-
 xen/arch/arm/vgic/vgic.c         | 15 ++++++++++
 xen/arch/arm/vgic/vgic.h         |  9 ++++++
 3 files changed, 86 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index 6f10cf16ca..43c1ab5906 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -20,9 +20,70 @@
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static unsigned long vgic_mmio_read_v2_misc(struct vcpu *vcpu,
+                                            paddr_t addr, unsigned int len)
+{
+    uint32_t value;
+
+    switch ( addr & 0x0c )      /* filter for the 4 registers handled here */
+    {
+    case GICD_CTLR:
+        value = vcpu->domain->arch.vgic.enabled ? GICD_CTL_ENABLE : 0;
+        break;
+    case GICD_TYPER:
+        value = vcpu->domain->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
+        value = (value >> 5) - 1;
+        value |= (vcpu->domain->max_vcpus - 1) << 5;
+        break;
+    case GICD_IIDR:
+        value = (PRODUCT_ID_KVM << 24) |
+                (VARIANT_ID_XEN << 16) |
+                (IMPLEMENTER_ARM << 0);
+        break;
+    default:
+        return 0;
+    }
+
+    return value;
+}
+
+static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
+                                    paddr_t addr, unsigned int len,
+                                    unsigned long val)
+{
+    struct vgic_dist *dist = &vcpu->domain->arch.vgic;
+    bool enabled;
+
+    switch ( addr & 0x0c )      /* filter for the 4 registers handled here */
+    {
+    case GICD_CTLR:
+        domain_lock(vcpu->domain);
+
+        /*
+         * Store the new enabled state in our distributor structure.
+         * Work out whether it was disabled before and now got enabled,
+         * so that we signal all VCPUs to check for interrupts to be injected.
+         */
+        enabled = dist->enabled;
+        dist->enabled = val & GICD_CTL_ENABLE;
+        enabled = !enabled && dist->enabled;
+
+        domain_unlock(vcpu->domain);
+
+        if ( enabled )
+            vgic_kick_vcpus(vcpu->domain);
+
+        break;
+    case GICD_TYPER:
+    case GICD_IIDR:
+        /* read-only, writes ignored */
+        return;
+    }
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
     REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
+        vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
         vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 925cda4580..37b425a16c 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -684,6 +684,21 @@ int vgic_vcpu_pending_irq(struct vcpu *vcpu)
     return ret;
 }
 
+void vgic_kick_vcpus(struct domain *d)
+{
+    struct vcpu *vcpu;
+
+    /*
+     * We've injected an interrupt, time to find out who deserves
+     * a good kick...
+     */
+    for_each_vcpu( d, vcpu )
+    {
+        if ( vgic_vcpu_pending_irq(vcpu) )
+            vcpu_kick(vcpu);
+    }
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index 7f221fd195..aed7e4179a 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -17,6 +17,14 @@
 #ifndef __XEN_ARM_VGIC_VGIC_H__
 #define __XEN_ARM_VGIC_VGIC_H__
 
+/*
+ * We piggy-back on the already used KVM product ID,  but use a different
+ * variant (major revision) for Xen.
+ */
+#define PRODUCT_ID_KVM          0x4b        /* ASCII code K */
+#define VARIANT_ID_XEN          0x01
+#define IMPLEMENTER_ARM         0x43b
+
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
 static inline bool irq_is_pending(struct vgic_irq *irq)
@@ -37,6 +45,7 @@ struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
 void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
 void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
                            unsigned long flags);
+void vgic_kick_vcpus(struct domain *d);
 
 static inline void vgic_get_irq_kref(struct vgic_irq *irq)
 {
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (17 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 21:06   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 20/39] ARM: new VGIC: Add PENDING " Andre Przywara
                   ` (19 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

As the enable register handlers are shared between the v2 and v3
emulation, their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.
This introduces a vgic_sync_hardware_irq() function, which updates the
physical side of a hardware mapped virtual IRQ.
Because the existing locking order between vgic_irq->irq_lock and
irq_desc->lock dictates so, we drop the irq_lock and retake them in the
proper order.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
Changelog v2 ... v3:
- fix indentation
- fix wording in comment
- add Reviewed-by:

Changelog v1 ... v2:
- ASSERT on h/w IRQ and vIRQ staying in sync

 xen/arch/arm/vgic/vgic-mmio-v2.c |   4 +-
 xen/arch/arm/vgic/vgic-mmio.c    | 117 +++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    |  11 ++++
 xen/arch/arm/vgic/vgic.c         |  40 +++++++++++++
 xen/arch/arm/vgic/vgic.h         |   3 +
 5 files changed, 173 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index 43c1ab5906..7efd1c4eb4 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -89,10 +89,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
         vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
index a03e8d88b9..f219b7c509 100644
--- a/xen/arch/arm/vgic/vgic-mmio.c
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -39,6 +39,123 @@ void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
     /* Ignore */
 }
 
+/*
+ * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
+ * of the enabled bit, so there is only one function for both here.
+ */
+unsigned long vgic_mmio_read_enable(struct vcpu *vcpu,
+                                    paddr_t addr, unsigned int len)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    uint32_t value = 0;
+    unsigned int i;
+
+    /* Loop over all IRQs affected by this read */
+    for ( i = 0; i < len * 8; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        if ( irq->enabled )
+            value |= (1U << i);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return value;
+}
+
+void vgic_mmio_write_senable(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    unsigned int i;
+
+    for_each_set_bit( i, &val, len * 8 )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+        unsigned long flags;
+        irq_desc_t *desc;
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        if ( irq->enabled )            /* skip already enabled IRQs */
+        {
+            spin_unlock_irqrestore(&irq->irq_lock, flags);
+            vgic_put_irq(vcpu->domain, irq);
+            continue;
+        }
+
+        irq->enabled = true;
+        if ( irq->hw )
+        {
+            /*
+             * The irq cannot be a PPI, we only support delivery
+             * of SPIs to guests.
+             */
+            ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
+
+            desc = irq_to_desc(irq->hwintid);
+        }
+        else
+            desc = NULL;
+
+        vgic_queue_irq_unlock(vcpu->domain, irq, flags);
+
+        if ( desc )
+            vgic_sync_hardware_irq(vcpu->domain, desc, irq);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
+void vgic_mmio_write_cenable(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    unsigned int i;
+
+    for_each_set_bit( i, &val, len * 8 )
+    {
+        struct vgic_irq *irq;
+        unsigned long flags;
+        irq_desc_t *desc;
+
+        irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        if ( !irq->enabled )            /* skip already disabled IRQs */
+        {
+            spin_unlock_irqrestore(&irq->irq_lock, flags);
+            vgic_put_irq(vcpu->domain, irq);
+            continue;
+        }
+
+        irq->enabled = false;
+
+        if ( irq->hw )
+        {
+            /*
+             * The irq cannot be a PPI, we only support delivery
+             * of SPIs to guests.
+             */
+            ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
+
+            desc = irq_to_desc(irq->hwintid);
+        }
+        else
+            desc = NULL;
+
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+        if ( desc )
+            vgic_sync_hardware_irq(vcpu->domain, desc, irq);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
 static int match_region(const void *key, const void *elt)
 {
     const unsigned int offset = (unsigned long)key;
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index c280668694..a2cebd77f4 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -86,6 +86,17 @@ unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
 void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
                         unsigned int len, unsigned long val);
 
+unsigned long vgic_mmio_read_enable(struct vcpu *vcpu,
+                                    paddr_t addr, unsigned int len);
+
+void vgic_mmio_write_senable(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val);
+
+void vgic_mmio_write_cenable(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 37b425a16c..90041eb071 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -699,6 +699,46 @@ void vgic_kick_vcpus(struct domain *d)
     }
 }
 
+static unsigned int translate_irq_type(bool is_level)
+{
+    return is_level ? IRQ_TYPE_LEVEL_HIGH : IRQ_TYPE_EDGE_RISING;
+}
+
+void vgic_sync_hardware_irq(struct domain *d,
+                            irq_desc_t *desc, struct vgic_irq *irq)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&desc->lock, flags);
+    spin_lock(&irq->irq_lock);
+
+    /*
+     * We forbid tinkering with the hardware IRQ association during
+     * a domain's lifetime.
+     */
+    ASSERT(irq->hw && desc->irq == irq->hwintid);
+
+    if ( irq->enabled )
+    {
+        /*
+         * We might end up from various callers, so check that the
+         * interrrupt is disabled before trying to change the config.
+         */
+        if ( irq_type_set_by_domain(d) &&
+             test_bit(_IRQ_DISABLED, &desc->status) )
+            gic_set_irq_type(desc, translate_irq_type(irq->config));
+
+        if ( irq->target_vcpu )
+            irq_set_affinity(desc, cpumask_of(irq->target_vcpu->processor));
+        desc->handler->enable(desc);
+    }
+    else
+        desc->handler->disable(desc);
+
+    spin_unlock(&irq->irq_lock);
+    spin_unlock_irqrestore(&desc->lock, flags);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index aed7e4179a..071e061066 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -55,6 +55,9 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
     atomic_inc(&irq->refcount);
 }
 
+void vgic_sync_hardware_irq(struct domain *d,
+                            irq_desc_t *desc, struct vgic_irq *irq);
+
 void vgic_v2_fold_lr_state(struct vcpu *vcpu);
 void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct vcpu *vcpu);
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 20/39] ARM: new VGIC: Add PENDING registers handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (18 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 21:14   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 21/39] ARM: new VGIC: Add ACTIVE " Andre Przywara
                   ` (18 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The pending register handlers are shared between the v2 and v3
emulation, so their implementation goes into vgic-mmio.c, to be easily
referenced from the v3 emulation as well later.
For level triggered interrupts the real line level is unaffected by
this write, so we keep this state separate and combine it with the
device's level to get the actual pending state.
Hardware mapped IRQs need some special handling, as their hardware state
has to be coordinated with the virtual pending bit to avoid hanging
or masked interrupts.

This is based on Linux commit 96b298000db4, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c |   4 +-
 xen/arch/arm/vgic/vgic-mmio.c    | 125 +++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    |  11 ++++
 3 files changed, 138 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index 7efd1c4eb4..a48c554040 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -95,10 +95,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
         vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
index f219b7c509..53b8978c02 100644
--- a/xen/arch/arm/vgic/vgic-mmio.c
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -156,6 +156,131 @@ void vgic_mmio_write_cenable(struct vcpu *vcpu,
     }
 }
 
+unsigned long vgic_mmio_read_pending(struct vcpu *vcpu,
+                                     paddr_t addr, unsigned int len)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    uint32_t value = 0;
+    unsigned int i;
+
+    /* Loop over all IRQs affected by this read */
+    for ( i = 0; i < len * 8; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        if ( irq_is_pending(irq) )
+            value |= (1U << i);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return value;
+}
+
+void vgic_mmio_write_spending(struct vcpu *vcpu,
+                              paddr_t addr, unsigned int len,
+                              unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    unsigned int i;
+    unsigned long flags;
+    irq_desc_t *desc;
+
+    for_each_set_bit( i, &val, len * 8 )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+        irq->pending_latch = true;
+
+        /* To observe the locking order, just take the irq_desc pointer here. */
+        if ( irq->hw )
+            desc = irq_to_desc(irq->hwintid);
+        else
+            desc = NULL;
+
+        vgic_queue_irq_unlock(vcpu->domain, irq, flags);
+
+        /*
+         * When the VM sets the pending state for a HW interrupt on the virtual
+         * distributor we set the active state on the physical distributor,
+         * because the virtual interrupt can become active and then the guest
+         * can deactivate it.
+         */
+        if ( desc )
+        {
+            spin_lock_irqsave(&desc->lock, flags);
+            spin_lock(&irq->irq_lock);
+
+            /* This h/w IRQ should still be assigned to the virtual IRQ. */
+            ASSERT(irq->hw && desc->irq == irq->hwintid);
+
+            gic_set_active_state(desc, true);
+
+            spin_unlock(&irq->irq_lock);
+            spin_unlock_irqrestore(&desc->lock, flags);
+        }
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
+void vgic_mmio_write_cpending(struct vcpu *vcpu,
+                              paddr_t addr, unsigned int len,
+                              unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    unsigned int i;
+    unsigned long flags;
+    irq_desc_t *desc;
+
+    for_each_set_bit( i, &val, len * 8 )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+        irq->pending_latch = false;
+
+        /* To observe the locking order, just take the irq_desc pointer here. */
+        if ( irq->hw )
+            desc = irq_to_desc(irq->hwintid);
+        else
+            desc = NULL;
+
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+        /*
+         * We don't want the guest to effectively mask the physical
+         * interrupt by doing a write to SPENDR followed by a write to
+         * CPENDR for HW interrupts, so we clear the active state on
+         * the physical side if the virtual interrupt is not active.
+         * This may lead to taking an additional interrupt on the
+         * host, but that should not be a problem as the worst that
+         * can happen is an additional vgic injection.  We also clear
+         * the pending state to maintain proper semantics for edge HW
+         * interrupts.
+         */
+        if ( desc )
+        {
+            spin_lock_irqsave(&desc->lock, flags);
+            spin_lock(&irq->irq_lock);
+
+            /* This h/w IRQ should still be assigned to the virtual IRQ. */
+            ASSERT(irq->hw && desc->irq == irq->hwintid);
+
+            gic_set_pending_state(desc, false);
+            if (!irq->active)
+                gic_set_active_state(desc, false);
+
+            spin_unlock(&irq->irq_lock);
+            spin_unlock_irqrestore(&desc->lock, flags);
+        }
+
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
 static int match_region(const void *key, const void *elt)
 {
     const unsigned int offset = (unsigned long)key;
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index a2cebd77f4..5c927f28b0 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -97,6 +97,17 @@ void vgic_mmio_write_cenable(struct vcpu *vcpu,
                              paddr_t addr, unsigned int len,
                              unsigned long val);
 
+unsigned long vgic_mmio_read_pending(struct vcpu *vcpu,
+                                     paddr_t addr, unsigned int len);
+
+void vgic_mmio_write_spending(struct vcpu *vcpu,
+                              paddr_t addr, unsigned int len,
+                              unsigned long val);
+
+void vgic_mmio_write_cpending(struct vcpu *vcpu,
+                              paddr_t addr, unsigned int len,
+                              unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 21/39] ARM: new VGIC: Add ACTIVE registers handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (19 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 20/39] ARM: new VGIC: Add PENDING " Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 21:21   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 22/39] ARM: new VGIC: Add PRIORITY " Andre Przywara
                   ` (17 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The active register handlers are shared between the v2 and v3 emulation,
so their implementation goes into vgic-mmio.c, to be easily referenced
from the v3 emulation as well later.
Since activation/deactivation of an interrupt may happen entirely in the
guest without it ever exiting, we need some extra logic to properly track
the active state.
For clearing the active state, we would basically have to halt the guest
to make sure this is properly propagated into the respective VCPUs.
This is not yet implemented in Xen.
Fortunately this feature is mostly used to reset a just in initialised
GIC, so chances are we are tasked to clear bits that are already zero.
Add a simple check to avoid pointless warnings in this case.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c |  4 +-
 xen/arch/arm/vgic/vgic-mmio.c    | 91 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    | 11 +++++
 3 files changed, 104 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index a48c554040..724681e0f8 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -101,10 +101,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICACTIVER,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
+        vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
         vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
index 53b8978c02..b79e431f50 100644
--- a/xen/arch/arm/vgic/vgic-mmio.c
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -281,6 +281,97 @@ void vgic_mmio_write_cpending(struct vcpu *vcpu,
     }
 }
 
+/*
+ * The actual active bit for a virtual IRQ is held in the LR. Our shadow
+ * copy in struct vgic_irq is only synced when needed and may not be
+ * up-to-date all of the time.
+ * Returning the actual active state is quite costly (stopping all
+ * VCPUs processing any affected vIRQs), so we use a simple implementation
+ * to get the best possible answer.
+ */
+unsigned long vgic_mmio_read_active(struct vcpu *vcpu,
+                                    paddr_t addr, unsigned int len)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    uint32_t value = 0;
+    unsigned int i;
+
+    /* Loop over all IRQs affected by this read */
+    for ( i = 0; i < len * 8; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        if ( irq->active )
+            value |= (1U << i);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return value;
+}
+
+/*
+ * We don't actually support clearing the active state of an IRQ (yet).
+ * However there is a chance that most guests use this for initialization.
+ * We check whether this MMIO access would actually affect any active IRQ,
+ * and only print our warning in this case. So clearing already non-active
+ * IRQs would not be moaned about in the logs.
+ */
+void vgic_mmio_write_cactive(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    unsigned int i;
+
+    for_each_set_bit( i, &val, len * 8 )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        /*
+         * If we know that the IRQ is active or we can't be sure about
+         * it (because it is currently in a CPU), log the not properly
+         * emulated MMIO access.
+         */
+        if ( irq->active || irq->vcpu )
+            printk(XENLOG_G_ERR
+                   "%pv: vGICD: IRQ%u: clearing active state not supported\n",
+                   vcpu, irq->intid);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
+/*
+ * We don't actually support setting the active state of an IRQ (yet).
+ * We check whether this MMIO access would actually affect any non-active IRQ,
+ * and only print our warning in this case.
+ */
+void vgic_mmio_write_sactive(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
+    unsigned int i;
+
+    for_each_set_bit( i, &val, len * 8 )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        /*
+         * If we know that the IRQ is not active or we can't be sure about
+         * it (because it is currently in a CPU), log the not properly
+         * emulated MMIO access.
+         */
+        if ( !irq->active || irq->vcpu )
+            printk(XENLOG_G_ERR
+                   "%pv: vGICD: IRQ%u: setting active state not supported\n",
+                   vcpu, irq->intid);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
 static int match_region(const void *key, const void *elt)
 {
     const unsigned int offset = (unsigned long)key;
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index 5c927f28b0..832e2eb3d8 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -108,6 +108,17 @@ void vgic_mmio_write_cpending(struct vcpu *vcpu,
                               paddr_t addr, unsigned int len,
                               unsigned long val);
 
+unsigned long vgic_mmio_read_active(struct vcpu *vcpu,
+                                    paddr_t addr, unsigned int len);
+
+void vgic_mmio_write_cactive(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val);
+
+void vgic_mmio_write_sactive(struct vcpu *vcpu,
+                             paddr_t addr, unsigned int len,
+                             unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 22/39] ARM: new VGIC: Add PRIORITY registers handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (20 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 21/39] ARM: new VGIC: Add ACTIVE " Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 21:24   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 23/39] ARM: new VGIC: Add CONFIG " Andre Przywara
                   ` (16 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The priority register handlers are shared between the v2 and v3 emulation,
so their implementation goes into vgic-mmio.c, to be easily referenced
from the v3 emulation as well later.

This is based on Linux commit 055658bf48fc, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c |  2 +-
 xen/arch/arm/vgic/vgic-mmio.c    | 47 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    |  7 ++++++
 xen/arch/arm/vgic/vgic.h         |  2 ++
 4 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index 724681e0f8..d2d6a07e1b 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -107,7 +107,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+        vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
         VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
         vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
index b79e431f50..14b69d80d4 100644
--- a/xen/arch/arm/vgic/vgic-mmio.c
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -372,6 +372,53 @@ void vgic_mmio_write_sactive(struct vcpu *vcpu,
     }
 }
 
+unsigned long vgic_mmio_read_priority(struct vcpu *vcpu,
+                                      paddr_t addr, unsigned int len)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
+    unsigned int i;
+    uint32_t val = 0;
+
+    for ( i = 0; i < len; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        val |= (uint32_t)irq->priority << (i * 8);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return val;
+}
+
+/*
+ * We currently don't handle changing the priority of an interrupt that
+ * is already pending on a VCPU. If there is a need for this, we would
+ * need to make this VCPU exit and re-evaluate the priorities, potentially
+ * leading to this interrupt getting presented now to the guest (if it has
+ * been masked by the priority mask before).
+ */
+void vgic_mmio_write_priority(struct vcpu *vcpu,
+                              paddr_t addr, unsigned int len,
+                              unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
+    unsigned int i;
+    unsigned long flags;
+
+    for ( i = 0; i < len; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+        /* Narrow the priority range to what we actually support */
+        irq->priority = (val >> (i * 8)) & GENMASK(7, 8 - VGIC_PRI_BITS);
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
 static int match_region(const void *key, const void *elt)
 {
     const unsigned int offset = (unsigned long)key;
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index 832e2eb3d8..b2d572d562 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -119,6 +119,13 @@ void vgic_mmio_write_sactive(struct vcpu *vcpu,
                              paddr_t addr, unsigned int len,
                              unsigned long val);
 
+unsigned long vgic_mmio_read_priority(struct vcpu *vcpu,
+                      paddr_t addr, unsigned int len);
+
+void vgic_mmio_write_priority(struct vcpu *vcpu,
+                  paddr_t addr, unsigned int len,
+                  unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index 071e061066..c7eeaf7a38 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -25,6 +25,8 @@
 #define VARIANT_ID_XEN          0x01
 #define IMPLEMENTER_ARM         0x43b
 
+#define VGIC_PRI_BITS       5
+
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
 
 static inline bool irq_is_pending(struct vgic_irq *irq)
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 23/39] ARM: new VGIC: Add CONFIG registers handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (21 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 22/39] ARM: new VGIC: Add PRIORITY " Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 21:26   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 24/39] ARM: new VGIC: Add TARGET " Andre Przywara
                   ` (15 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The config register handlers are shared between the v2 and v3 emulation,
so their implementation goes into vgic-mmio.c, to be easily referenced
from the v3 emulation as well later.

This is based on Linux commit 79717e4ac09c, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c |  2 +-
 xen/arch/arm/vgic/vgic-mmio.c    | 54 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic-mmio.h    |  7 ++++++
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index d2d6a07e1b..a28d0e459b 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -113,7 +113,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
         VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 2,
+        vgic_mmio_read_config, vgic_mmio_write_config, 2,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
         vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
index 14b69d80d4..5bcb02e8c6 100644
--- a/xen/arch/arm/vgic/vgic-mmio.c
+++ b/xen/arch/arm/vgic/vgic-mmio.c
@@ -419,6 +419,60 @@ void vgic_mmio_write_priority(struct vcpu *vcpu,
     }
 }
 
+unsigned long vgic_mmio_read_config(struct vcpu *vcpu,
+                                    paddr_t addr, unsigned int len)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 2);
+    uint32_t value = 0;
+    int i;
+
+    for ( i = 0; i < len * 4; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        if ( irq->config == VGIC_CONFIG_EDGE )
+            value |= (2U << (i * 2));
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return value;
+}
+
+void vgic_mmio_write_config(struct vcpu *vcpu,
+                            paddr_t addr, unsigned int len,
+                            unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 2);
+    int i;
+    unsigned long flags;
+
+    for ( i = 0; i < len * 4; i++ )
+    {
+        struct vgic_irq *irq;
+
+        /*
+         * The configuration cannot be changed for SGIs in general,
+         * for PPIs this is IMPLEMENTATION DEFINED. The arch timer
+         * code relies on PPIs being level triggered, so we also
+         * make them read-only here.
+         */
+        if ( intid + i < VGIC_NR_PRIVATE_IRQS )
+            continue;
+
+        irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        if ( test_bit(i * 2 + 1, &val) )
+            irq->config = VGIC_CONFIG_EDGE;
+        else
+            irq->config = VGIC_CONFIG_LEVEL;
+
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
 static int match_region(const void *key, const void *elt)
 {
     const unsigned int offset = (unsigned long)key;
diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
index b2d572d562..3566cf237c 100644
--- a/xen/arch/arm/vgic/vgic-mmio.h
+++ b/xen/arch/arm/vgic/vgic-mmio.h
@@ -126,6 +126,13 @@ void vgic_mmio_write_priority(struct vcpu *vcpu,
                   paddr_t addr, unsigned int len,
                   unsigned long val);
 
+unsigned long vgic_mmio_read_config(struct vcpu *vcpu,
+                    paddr_t addr, unsigned int len);
+
+void vgic_mmio_write_config(struct vcpu *vcpu,
+                paddr_t addr, unsigned int len,
+                unsigned long val);
+
 unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
 
 #endif
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 24/39] ARM: new VGIC: Add TARGET registers handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (22 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 23/39] ARM: new VGIC: Add CONFIG " Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27  0:24   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler Andre Przywara
                   ` (14 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The target register handlers are v2 emulation specific, so their
implementation lives entirely in vgic-mmio-v2.c.
We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
set in the target mask instead of making it possibly pending on
multiple VCPUs.
We update the physical affinity of a hardware mapped vIRQ on the way.

This is based on Linux commit 2c234d6f1826, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c | 59 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index a28d0e459b..b333de9ed7 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -81,6 +81,63 @@ static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
     }
 }
 
+static unsigned long vgic_mmio_read_target(struct vcpu *vcpu,
+                                           paddr_t addr, unsigned int len)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
+    uint32_t val = 0;
+    unsigned int i;
+
+    for ( i = 0; i < len; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        val |= (uint32_t)irq->targets << (i * 8);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return val;
+}
+
+static void vgic_mmio_write_target(struct vcpu *vcpu,
+                                   paddr_t addr, unsigned int len,
+                                   unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
+    uint8_t cpu_mask = GENMASK(vcpu->domain->max_vcpus - 1, 0);
+    unsigned int i;
+    unsigned long flags;
+
+    /* GICD_ITARGETSR[0-7] are read-only */
+    if ( intid < VGIC_NR_PRIVATE_IRQS )
+        return;
+
+    for ( i = 0; i < len; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, NULL, intid + i);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        irq->targets = (val >> (i * 8)) & cpu_mask;
+        if ( irq->targets )
+        {
+            irq->target_vcpu = vcpu->domain->vcpu[ffs(irq->targets) - 1];
+            if ( irq->hw )
+            {
+                struct irq_desc *desc = irq_to_desc(irq->hwintid);
+
+                irq_set_affinity(desc, cpumask_of(irq->target_vcpu->processor));
+            }
+        }
+        else
+            irq->target_vcpu = NULL;
+
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
     REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
         vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
@@ -110,7 +167,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
         VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
+        vgic_mmio_read_target, vgic_mmio_write_target, 8,
         VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
     REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
         vgic_mmio_read_config, vgic_mmio_write_config, 2,
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (23 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 24/39] ARM: new VGIC: Add TARGET " Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  7:54   ` Julien Grall
  2018-03-27 22:23   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers Andre Przywara
                   ` (13 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Triggering an IPI via this register is v2 specific, so the
implementation lives entirely in vgic-mmio-v2.c.

This is based on Linux commit 55cc01fb9004, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- fix target mask calculation

Changelog v1 ... v2:
- remove stray rebase artefact

 xen/arch/arm/vgic/vgic-mmio-v2.c | 45 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index b333de9ed7..9ef80608c1 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -81,6 +81,49 @@ static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
     }
 }
 
+static void vgic_mmio_write_sgir(struct vcpu *source_vcpu,
+                                 paddr_t addr, unsigned int len,
+                                 unsigned long val)
+{
+    struct domain *d = source_vcpu->domain;
+    unsigned int nr_vcpus = d->max_vcpus;
+    unsigned int intid = val & GICD_SGI_INTID_MASK;
+    unsigned long targets = (val & GICD_SGI_TARGET_MASK) >>
+                            GICD_SGI_TARGET_SHIFT;
+    unsigned int vcpu_id;
+
+    switch ( val & GICD_SGI_TARGET_LIST_MASK )
+    {
+    case GICD_SGI_TARGET_LIST:                    /* as specified by targets */
+        targets &= GENMASK(nr_vcpus - 1, 0);      /* limit to existing VCPUs */
+        break;
+    case GICD_SGI_TARGET_OTHERS:
+        targets = GENMASK(nr_vcpus - 1, 0);       /* all, ...   */
+        targets &= ~(1U << source_vcpu->vcpu_id); /*   but self */
+        break;
+    case GICD_SGI_TARGET_SELF:                    /* this very vCPU only */
+        targets = (1U << source_vcpu->vcpu_id);
+        break;
+    case 0x3:                                     /* reserved */
+        return;
+    }
+
+    for_each_set_bit( vcpu_id, &targets, 8 )
+    {
+        struct vcpu *vcpu = d->vcpu[vcpu_id];
+        struct vgic_irq *irq = vgic_get_irq(d, vcpu, intid);
+        unsigned long flags;
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        irq->pending_latch = true;
+        irq->source |= 1U << source_vcpu->vcpu_id;
+
+        vgic_queue_irq_unlock(d, irq, flags);
+        vgic_put_irq(d, irq);
+    }
+}
+
 static unsigned long vgic_mmio_read_target(struct vcpu *vcpu,
                                            paddr_t addr, unsigned int len)
 {
@@ -173,7 +216,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_config, vgic_mmio_write_config, 2,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
+        vgic_mmio_read_raz, vgic_mmio_write_sgir, 4,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
         vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (24 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:27   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 27/39] ARM: new VGIC: Handle hardware mapped IRQs Andre Przywara
                   ` (12 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

As this register is v2 specific, its implementation lives entirely
in vgic-mmio-v2.c.
This register allows setting the source mask of an IPI.

This is based on Linux commit ed40213ef9b0, written by Andre Przywara.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-mmio-v2.c | 81 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 79 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
index 9ef80608c1..32e0f6fc33 100644
--- a/xen/arch/arm/vgic/vgic-mmio-v2.c
+++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
@@ -181,6 +181,83 @@ static void vgic_mmio_write_target(struct vcpu *vcpu,
     }
 }
 
+static unsigned long vgic_mmio_read_sgipend(struct vcpu *vcpu,
+                                            paddr_t addr, unsigned int len)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
+    uint32_t val = 0;
+    unsigned int i;
+
+    ASSERT(intid < VGIC_NR_SGIS);
+
+    for ( i = 0; i < len; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        val |= (uint32_t)irq->source << (i * 8);
+
+        vgic_put_irq(vcpu->domain, irq);
+    }
+
+    return val;
+}
+
+static void vgic_mmio_write_sgipendc(struct vcpu *vcpu,
+                                     paddr_t addr, unsigned int len,
+                                     unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
+    unsigned int i;
+    unsigned long flags;
+
+    ASSERT(intid < VGIC_NR_SGIS);
+
+    for ( i = 0; i < len; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        irq->source &= ~((val >> (i * 8)) & 0xff);
+        if ( !irq->source )
+            irq->pending_latch = false;
+
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
+static void vgic_mmio_write_sgipends(struct vcpu *vcpu,
+                                     paddr_t addr, unsigned int len,
+                                     unsigned long val)
+{
+    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
+    unsigned int i;
+    unsigned long flags;
+
+    ASSERT(intid < VGIC_NR_SGIS);
+
+    for ( i = 0; i < len; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        irq->source |= (val >> (i * 8)) & 0xff;
+
+        if ( irq->source )
+        {
+            irq->pending_latch = true;
+            vgic_queue_irq_unlock(vcpu->domain, irq, flags);
+        }
+        else
+        {
+            spin_unlock_irqrestore(&irq->irq_lock, flags);
+        }
+        vgic_put_irq(vcpu->domain, irq);
+    }
+}
+
 static const struct vgic_register_region vgic_v2_dist_registers[] = {
     REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
         vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
@@ -219,10 +296,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
         vgic_mmio_read_raz, vgic_mmio_write_sgir, 4,
         VGIC_ACCESS_32bit),
     REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
+        vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16,
         VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
     REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
-        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
+        vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16,
         VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
 };
 
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 27/39] ARM: new VGIC: Handle hardware mapped IRQs
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (25 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:31   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 28/39] ARM: new VGIC: Add event channel IRQ handling Andre Przywara
                   ` (11 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The VGIC supports virtual IRQs to be connected to a hardware IRQ, so
when a guest EOIs the virtual interrupt, it affects the state of that
corresponding interrupt on the hardware side at the same time.
Implement the interface that the Xen arch/core code expects to connect
the virtual and the physical world.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 90041eb071..07866d7243 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -699,6 +699,77 @@ void vgic_kick_vcpus(struct domain *d)
     }
 }
 
+struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
+                                      unsigned int virq)
+{
+    struct irq_desc *desc = NULL;
+    struct vgic_irq *irq = vgic_get_irq(d, v, virq);
+    unsigned long flags;
+
+    if ( !irq )
+        return NULL;
+
+    spin_lock_irqsave(&irq->irq_lock, flags);
+    if ( irq->hw )
+    {
+        ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
+        desc = irq_to_desc(irq->hwintid);
+    }
+    spin_unlock_irqrestore(&irq->irq_lock, flags);
+
+    vgic_put_irq(d, irq);
+
+    return desc;
+}
+
+/*
+ * was:
+ *      int kvm_vgic_map_phys_irq(struct vcpu *vcpu, u32 virt_irq, u32 phys_irq)
+ *      int kvm_vgic_unmap_phys_irq(struct vcpu *vcpu, unsigned int virt_irq)
+ */
+int vgic_connect_hw_irq(struct domain *d, struct vcpu *vcpu,
+                        unsigned int virt_irq, struct irq_desc *desc,
+                        bool connect)
+{
+    struct vgic_irq *irq = vgic_get_irq(d, vcpu, virt_irq);
+    unsigned long flags;
+    int ret = 0;
+
+    if ( !irq )
+        return -EINVAL;
+
+    spin_lock_irqsave(&irq->irq_lock, flags);
+
+    if ( connect )                      /* assign a mapped IRQ */
+    {
+        /* The VIRQ should not be already enabled by the guest */
+        if ( !irq->hw && !irq->enabled )
+        {
+            irq->hw = true;
+            irq->hwintid = desc->irq;
+        }
+        else
+            ret = -EBUSY;
+    }
+    else                                /* remove a mapped IRQ */
+    {
+        if ( desc && irq->hwintid != desc->irq )
+        {
+            ret = -EINVAL;
+        }
+        else
+        {
+            irq->hw = false;
+            irq->hwintid = 0;
+        }
+    }
+
+    spin_unlock_irqrestore(&irq->irq_lock, flags);
+    vgic_put_irq(d, irq);
+
+    return ret;
+}
+
 static unsigned int translate_irq_type(bool is_level)
 {
     return is_level ? IRQ_TYPE_LEVEL_HIGH : IRQ_TYPE_EDGE_RISING;
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 28/39] ARM: new VGIC: Add event channel IRQ handling
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (26 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 27/39] ARM: new VGIC: Handle hardware mapped IRQs Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:33   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 29/39] ARM: new VGIC: Handle virtual IRQ allocation/reservation Andre Przywara
                   ` (10 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The Xen core/arch code relies on two abstracted functions to inject an
event channel IRQ and to query its pending state.
Implement those to query the state of the new VGIC implementation.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 07866d7243..3d818a98ad 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -699,6 +699,29 @@ void vgic_kick_vcpus(struct domain *d)
     }
 }
 
+void arch_evtchn_inject(struct vcpu *v)
+{
+    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
+}
+
+bool vgic_evtchn_irq_pending(struct vcpu *v)
+{
+    struct vgic_irq *irq;
+    unsigned long flags;
+    bool pending;
+
+    /* Does not work for LPIs. */
+    ASSERT(!is_lpi(v->domain->arch.evtchn_irq));
+
+    irq = vgic_get_irq(v->domain, v, v->domain->arch.evtchn_irq);
+    spin_lock_irqsave(&irq->irq_lock, flags);
+    pending = irq_is_pending(irq);
+    spin_unlock_irqrestore(&irq->irq_lock, flags);
+    vgic_put_irq(v->domain, irq);
+
+    return pending;
+}
+
 struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
                                       unsigned int virq)
 {
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 29/39] ARM: new VGIC: Handle virtual IRQ allocation/reservation
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (27 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 28/39] ARM: new VGIC: Add event channel IRQ handling Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:38   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 30/39] ARM: new VGIC: Dump virtual IRQ info Andre Przywara
                   ` (9 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

To find an unused virtual IRQ number Xen uses a scheme to track used
virtual IRQs.
Implement this interface in the new VGIC to make the Xen core/arch code
happy.
This is actually somewhat VGIC agnostic, so is mostly a copy of the code
from the old VGIC. But it has to live in the VGIC files, so we can't
easily reuse the existing implementation.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 3d818a98ad..8aaad4bffa 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -722,6 +722,50 @@ bool vgic_evtchn_irq_pending(struct vcpu *v)
     return pending;
 }
 
+bool vgic_reserve_virq(struct domain *d, unsigned int virq)
+{
+    if ( virq >= vgic_num_irqs(d) )
+        return false;
+
+    return !test_and_set_bit(virq, d->arch.vgic.allocated_irqs);
+}
+
+int vgic_allocate_virq(struct domain *d, bool spi)
+{
+    int first, end;
+    unsigned int virq;
+
+    if ( !spi )
+    {
+        /* We only allocate PPIs. SGIs are all reserved */
+        first = 16;
+        end = 32;
+    }
+    else
+    {
+        first = 32;
+        end = vgic_num_irqs(d);
+    }
+
+    /*
+     * There is no spinlock to protect allocated_irqs, therefore
+     * test_and_set_bit may fail. If so retry it.
+     */
+    do
+    {
+        virq = find_next_zero_bit(d->arch.vgic.allocated_irqs, end, first);
+        if ( virq >= end )
+            return -1;
+    } while ( test_and_set_bit(virq, d->arch.vgic.allocated_irqs) );
+
+    return virq;
+}
+
+void vgic_free_virq(struct domain *d, unsigned int virq)
+{
+    clear_bit(virq, d->arch.vgic.allocated_irqs);
+}
+
 struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
                                       unsigned int virq)
 {
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 30/39] ARM: new VGIC: Dump virtual IRQ info
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (28 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 29/39] ARM: new VGIC: Handle virtual IRQ allocation/reservation Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:39   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 31/39] ARM: new VGIC: Provide system register emulation stub Andre Przywara
                   ` (8 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

When we dump guest state on the Xen console, we also print the state of
IRQs that are on a VCPU.
Add the code to dump the state of an IRQ handled by the new VGIC.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 8aaad4bffa..79c6a5553d 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -766,6 +766,31 @@ void vgic_free_virq(struct domain *d, unsigned int virq)
     clear_bit(virq, d->arch.vgic.allocated_irqs);
 }
 
+void gic_dump_vgic_info(struct vcpu *v)
+{
+    struct vgic_cpu *vgic_cpu = &v->arch.vgic;
+    struct vgic_irq *irq;
+    unsigned long flags;
+
+    spin_lock_irqsave(&v->arch.vgic.ap_list_lock, flags);
+
+    if ( !list_empty(&vgic_cpu->ap_list_head) )
+        printk("   active or pending interrupts queued:\n");
+
+    list_for_each_entry ( irq, &vgic_cpu->ap_list_head, ap_list )
+    {
+        spin_lock(&irq->irq_lock);
+        printk("     %s %s irq %u: %spending, %sactive, %senabled\n",
+               irq->hw ? "hardware" : "virtual",
+               irq->config == VGIC_CONFIG_LEVEL ? "level" : "edge",
+               irq->intid, irq_is_pending(irq) ? "" : "not ",
+               irq->active ? "" : "not ", irq->enabled ? "" : "not ");
+        spin_unlock(&irq->irq_lock);
+    }
+
+    spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
+}
+
 struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
                                       unsigned int virq)
 {
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 31/39] ARM: new VGIC: Provide system register emulation stub
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (29 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 30/39] ARM: new VGIC: Dump virtual IRQ info Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:40   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs() Andre Przywara
                   ` (7 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The Xen arch code traps system registers writes from the guest and will
relay anything GIC related to the VGIC.
Since this affects only GICv3 (which we don't yet emulate), provide a
stub implementation of vgic_emulate() for now.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 79c6a5553d..ffab0b2635 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -814,6 +814,13 @@ struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
     return desc;
 }
 
+bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
+{
+    ASSERT(current->domain->arch.vgic.version == GIC_V3);
+
+    return false;
+}
+
 /*
  * was:
  *      int kvm_vgic_map_phys_irq(struct vcpu *vcpu, u32 virt_irq, u32 phys_irq)
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs()
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (30 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 31/39] ARM: new VGIC: Provide system register emulation stub Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-26 23:46   ` Stefano Stabellini
  2018-03-28 18:47   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 33/39] ARM: new VGIC: Add preliminary stub implementation Andre Przywara
                   ` (6 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

When a VCPU moves to another CPU, we need to adjust the target affinity
of any hardware mapped vIRQs, to observe our "physical-follows-virtual"
policy.
Implement arch_move_irqs() to adjust the physical affinity of all hardware
mapped vIRQs targetting this VCPU.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index ffab0b2635..23b8abfc5e 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -791,6 +791,45 @@ void gic_dump_vgic_info(struct vcpu *v)
     spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
 }
 
+/**
+ * arch_move_irqs() - migrate the physical affinity of hardware mapped vIRQs
+ * @v:  the vCPU, already assigned to the new pCPU
+ *
+ * arch_move_irqs() updates the physical affinity of all virtual IRQs
+ * targetting this given vCPU. This only affects hardware mapped IRQs. The
+ * new pCPU to target is already set in v->processor.
+ * This is called by the core code after a vCPU has been migrated to a new
+ * physical CPU.
+ */
+void arch_move_irqs(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    unsigned int i;
+
+    /* We only target SPIs with this function */
+    for ( i = 0; i < d->arch.vgic.nr_spis; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(d, NULL, i + VGIC_NR_PRIVATE_IRQS);
+        unsigned long flags;
+
+        if ( !irq )
+            continue;
+
+        spin_lock_irqsave(&irq->irq_lock, flags);
+
+        /* only vIRQs that are not on a vCPU yet , but targetting this vCPU */
+        if ( irq->hw && !irq->vcpu && irq->target_vcpu == v)
+        {
+            irq_desc_t *desc = irq_to_desc(irq->hwintid);
+
+            irq_set_affinity(desc, cpumask_of(v->processor));
+        }
+
+        spin_unlock_irqrestore(&irq->irq_lock, flags);
+        vgic_put_irq(d, irq);
+    }
+}
+
 struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
                                       unsigned int virq)
 {
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 33/39] ARM: new VGIC: Add preliminary stub implementation
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (31 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs() Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:48   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC Andre Przywara
                   ` (5 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

The ARM arch code requires an interrupt controller emulation to implement
vgic_clear_pending_irqs(), although it is suspected that it is actually
not necessary. Go with a stub for now to make the linker happy.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Reviewed-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 23b8abfc5e..b70fdaaecb 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -791,6 +791,14 @@ void gic_dump_vgic_info(struct vcpu *v)
     spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
 }
 
+void vgic_clear_pending_irqs(struct vcpu *v)
+{
+    /*
+     * TODO: It is unclear whether we really need this, so we might instead
+     * remove it on the caller site.
+     */
+}
+
 /**
  * arch_move_irqs() - migrate the physical affinity of hardware mapped vIRQs
  * @v:  the vCPU, already assigned to the new pCPU
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (32 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 33/39] ARM: new VGIC: Add preliminary stub implementation Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  8:00   ` Julien Grall
  2018-03-21 16:32 ` [PATCH v3 35/39] ARM: new VGIC: Add vgic_v2_enable Andre Przywara
                   ` (4 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

This patch implements the function which is called by Xen when it wants
to register the virtual GIC.
This also implements vgic_max_vcpus() for the new VGIC, which reports
back the maximum number of VCPUs a certain GIC model supports. Similar
to the counterpart in the "old" VGIC, we return some maximum value if
the VGIC has not been initialised yet.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- drop premature #ifdef CONFIG_HAS_GICV3
- use new GIC_INVALID to detect uninitialised VGIC

 xen/arch/arm/vgic/vgic-init.c | 60 +++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.c      | 25 ++++++++++++++++++
 xen/arch/arm/vgic/vgic.h      |  3 +++
 3 files changed, 88 insertions(+)
 create mode 100644 xen/arch/arm/vgic/vgic-init.c

diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
new file mode 100644
index 0000000000..d091c92ed0
--- /dev/null
+++ b/xen/arch/arm/vgic/vgic-init.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015, 2016 ARM Ltd.
+ * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
+ *
+ * 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/sched.h>
+#include <asm/new_vgic.h>
+
+#include "vgic.h"
+
+/* CREATION */
+
+/**
+ * domain_vgic_register: create a virtual GIC
+ * @d: domain pointer
+ * @mmio_count: pointer to add number of required MMIO regions
+ *
+ * was: kvm_vgic_create
+ */
+int domain_vgic_register(struct domain *d, int *mmio_count)
+{
+    switch ( d->arch.vgic.version )
+    {
+    case GIC_V2:
+        *mmio_count = 1;
+        break;
+    default:
+        BUG();
+    }
+
+    if ( d->max_vcpus > domain_max_vcpus(d) )
+        return -E2BIG;
+
+    d->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
+    d->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
+    d->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index b70fdaaecb..131358a5a1 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -956,6 +956,31 @@ void vgic_sync_hardware_irq(struct domain *d,
     spin_unlock_irqrestore(&desc->lock, flags);
 }
 
+unsigned int vgic_max_vcpus(const struct domain *d)
+{
+    unsigned int vgic_vcpu_limit;
+
+    switch ( d->arch.vgic.version )
+    {
+    case GIC_INVALID:
+        /*
+         * Since evtchn_init would call domain_max_vcpus for poll_mask
+         * allocation before the VGIC has been initialised, we need to
+         * return some safe value in this case. As this is for allocation
+         * purposes, go with the maximum value.
+         */
+        vgic_vcpu_limit = MAX_VIRT_CPUS;
+        break;
+    case GIC_V2:
+        vgic_vcpu_limit = VGIC_V2_MAX_CPUS;
+        break;
+    default:
+        BUG();
+    }
+
+    return min_t(unsigned int, MAX_VIRT_CPUS, vgic_vcpu_limit);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index c7eeaf7a38..a3fcd4d965 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -25,6 +25,9 @@
 #define VARIANT_ID_XEN          0x01
 #define IMPLEMENTER_ARM         0x43b
 
+#define VGIC_ADDR_UNDEF     INVALID_PADDR
+#define IS_VGIC_ADDR_UNDEF(_x)  ((_x) == VGIC_ADDR_UNDEF)
+
 #define VGIC_PRI_BITS       5
 
 #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 35/39] ARM: new VGIC: Add vgic_v2_enable
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (33 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 22:51   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init Andre Przywara
                   ` (3 subsequent siblings)
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

Enable the VGIC operation by properly initialising the registers
in the hypervisor GIC interface.

This is based on Linux commit f7b6985cc3d0, written by Eric Auger.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Acked-by: Julien Grall <julien.grall@arm.com>
---
Changelog v2 ... v3:
- replace "1" with "true" in boolean parameter

Changelog v1 ... v2:
- move patch from later part in the series

 xen/arch/arm/vgic/vgic-v2.c | 6 ++++++
 xen/arch/arm/vgic/vgic.h    | 1 +
 2 files changed, 7 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c
index 8ab0cfe81d..ce77e58857 100644
--- a/xen/arch/arm/vgic/vgic-v2.c
+++ b/xen/arch/arm/vgic/vgic-v2.c
@@ -229,6 +229,12 @@ void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr)
     gic_hw_ops->write_lr(lr, &lr_val);
 }
 
+void vgic_v2_enable(struct vcpu *vcpu)
+{
+    /* Get the show on the road... */
+    gic_hw_ops->update_hcr_status(GICH_HCR_EN, true);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index a3fcd4d965..112952fbf9 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -66,6 +66,7 @@ void vgic_sync_hardware_irq(struct domain *d,
 void vgic_v2_fold_lr_state(struct vcpu *vcpu);
 void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct vcpu *vcpu);
+void vgic_v2_enable(struct vcpu *vcpu);
 int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
                              enum vgic_type);
 
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (34 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 35/39] ARM: new VGIC: Add vgic_v2_enable Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  8:01   ` Julien Grall
  2018-03-27 23:16   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 37/39] ARM: new VGIC: vgic-init: implement map_resources Andre Przywara
                   ` (2 subsequent siblings)
  38 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

This patch allocates and initializes the data structures used to model
the vgic distributor and virtual cpu interfaces. At that stage the
number of IRQs and number of virtual CPUs is frozen.
Implement the various functions that the Xen arch code is expecting to
call during domain and VCPU setup to initialize the VGIC.
Their prototypes are already in existing header files.

This is based on Linux commit ad275b8bb1e6, written by Eric Auger.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- move ROUNDUP(nr_spis) call before boundary check

Changelog v1 ... v2:
- remove stray kvm_ prefix in comment
- use unsigned int
- ROUNDUP number of SPIs
- fix indentation

 xen/arch/arm/vgic/vgic-init.c | 201 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 201 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
index d091c92ed0..bfd3d09edb 100644
--- a/xen/arch/arm/vgic/vgic-init.c
+++ b/xen/arch/arm/vgic/vgic-init.c
@@ -15,11 +15,83 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <xen/lib.h>
 #include <xen/sched.h>
 #include <asm/new_vgic.h>
 
 #include "vgic.h"
 
+/*
+ * Initialization rules: there are multiple stages to the vgic
+ * initialization, both for the distributor and the CPU interfaces.  The basic
+ * idea is that even though the VGIC is not functional or not requested from
+ * user space, the critical path of the run loop can still call VGIC functions
+ * that just won't do anything, without them having to check additional
+ * initialization flags to ensure they don't look at uninitialized data
+ * structures.
+ *
+ * Distributor:
+ *
+ * - vgic_early_init(): initialization of static data that doesn't
+ *   depend on any sizing information or emulation type. No allocation
+ *   is allowed there.
+ *
+ * - vgic_init(): allocation and initialization of the generic data
+ *   structures that depend on sizing information (number of CPUs,
+ *   number of interrupts). Also initializes the vcpu specific data
+ *   structures. Can be executed lazily for GICv2.
+ *
+ * CPU Interface:
+ *
+ * - vgic_vcpu_early_init(): initialization of static data that
+ *   doesn't depend on any sizing information or emulation type. No
+ *   allocation is allowed there.
+ */
+
+/**
+ * vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
+ * @vcpu: The VCPU whose VGIC data structures whould be initialized
+ *
+ * Only do initialization, but do not actually enable the VGIC CPU interface
+ * yet.
+ */
+static void vgic_vcpu_early_init(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+    unsigned int i;
+
+    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+    spin_lock_init(&vgic_cpu->ap_list_lock);
+
+    /*
+     * Enable and configure all SGIs to be edge-triggered and
+     * configure all PPIs as level-triggered.
+     */
+    for ( i = 0; i < VGIC_NR_PRIVATE_IRQS; i++ )
+    {
+        struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
+
+        INIT_LIST_HEAD(&irq->ap_list);
+        spin_lock_init(&irq->irq_lock);
+        irq->intid = i;
+        irq->vcpu = NULL;
+        irq->target_vcpu = vcpu;
+        irq->targets = 1U << vcpu->vcpu_id;
+        atomic_set(&irq->refcount, 0);
+        if ( vgic_irq_is_sgi(i) )
+        {
+            /* SGIs */
+            irq->enabled = 1;
+            irq->config = VGIC_CONFIG_EDGE;
+        }
+        else
+        {
+            /* PPIs */
+            irq->config = VGIC_CONFIG_LEVEL;
+        }
+    }
+}
+
 /* CREATION */
 
 /**
@@ -50,6 +122,135 @@ int domain_vgic_register(struct domain *d, int *mmio_count)
     return 0;
 }
 
+/* INIT/DESTROY */
+
+/**
+ * domain_vgic_init: initialize the dist data structures
+ * @d: domain pointer
+ * @nr_spis: number of SPIs
+ */
+int domain_vgic_init(struct domain *d, unsigned int nr_spis)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+    unsigned int i;
+    int ret;
+
+    /* The number of SPIs must be a multiple of 32 per the GIC spec. */
+    nr_spis = ROUNDUP(nr_spis, 32);
+
+    /* Limit the number of virtual SPIs supported to (1020 - 32) = 988  */
+    if ( nr_spis > (1020 - NR_LOCAL_IRQS) )
+        return -EINVAL;
+
+    dist->nr_spis = nr_spis;
+    dist->spis = xzalloc_array(struct vgic_irq, nr_spis);
+    if ( !dist->spis )
+        return  -ENOMEM;
+
+    /*
+     * In the following code we do not take the irq struct lock since
+     * no other action on irq structs can happen while the VGIC is
+     * not initialized yet:
+     * If someone wants to inject an interrupt or does a MMIO access, we
+     * require prior initialization in case of a virtual GICv3 or trigger
+     * initialization when using a virtual GICv2.
+     */
+    for ( i = 0; i < nr_spis; i++ )
+    {
+        struct vgic_irq *irq = &dist->spis[i];
+
+        irq->intid = i + VGIC_NR_PRIVATE_IRQS;
+        INIT_LIST_HEAD(&irq->ap_list);
+        spin_lock_init(&irq->irq_lock);
+        irq->vcpu = NULL;
+        irq->target_vcpu = NULL;
+        atomic_set(&irq->refcount, 0);
+        if ( dist->version == GIC_V2 )
+            irq->targets = 0;
+        else
+            irq->mpidr = 0;
+    }
+
+    INIT_LIST_HEAD(&dist->lpi_list_head);
+    spin_lock_init(&dist->lpi_list_lock);
+
+    if ( dist->version == GIC_V2 )
+        ret = vgic_v2_map_resources(d);
+    else
+        ret = -ENXIO;
+
+    if ( ret )
+        return ret;
+
+    /* allocated_irqs() is used by Xen to find available vIRQs */
+    d->arch.vgic.allocated_irqs =
+        xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d)));
+    if ( !d->arch.vgic.allocated_irqs )
+        return -ENOMEM;
+
+    /* vIRQ0-15 (SGIs) are reserved */
+    for ( i = 0; i < NR_GIC_SGI; i++ )
+        set_bit(i, d->arch.vgic.allocated_irqs);
+
+    return 0;
+}
+
+/**
+ * vcpu_vgic_init() - Register VCPU-specific KVM iodevs
+ * was: kvm_vgic_vcpu_init()
+ * Xen: adding vgic_vx_enable() call
+ * @vcpu: pointer to the VCPU being created and initialized
+ */
+int vcpu_vgic_init(struct vcpu *vcpu)
+{
+    int ret = 0;
+
+    vgic_vcpu_early_init(vcpu);
+
+    if ( gic_hw_version() == GIC_V2 )
+        vgic_v2_enable(vcpu);
+    else
+        ret = -ENXIO;
+
+    return ret;
+}
+
+void domain_vgic_free(struct domain *d)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+        int i, ret;
+
+    for ( i = 0; i < dist->nr_spis; i++ )
+    {
+        struct vgic_irq *irq = vgic_get_irq(d, NULL, 32 + i);
+
+        if ( !irq->hw )
+            continue;
+
+        ret = release_guest_irq(d, irq->hwintid);
+        if ( ret )
+            dprintk(XENLOG_G_WARNING,
+                    "d%u: Failed to release virq %u ret = %d\n",
+                    d->domain_id, 32 + i, ret);
+    }
+
+    dist->ready = false;
+    dist->initialized = false;
+
+    xfree(dist->spis);
+    xfree(dist->allocated_irqs);
+    dist->nr_spis = 0;
+}
+
+int vcpu_vgic_free(struct vcpu *vcpu)
+{
+    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
+
+    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
+
+    return 0;
+}
+
 /*
  * Local variables:
  * mode: C
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 37/39] ARM: new VGIC: vgic-init: implement map_resources
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (35 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-27 23:09   ` Stefano Stabellini
  2018-03-21 16:32 ` [PATCH v3 38/39] ARM: new VGIC: Allocate two pages for struct vcpu Andre Przywara
  2018-03-21 16:32 ` [PATCH v3 39/39] ARM: VGIC: wire new VGIC(-v2) files into Xen build system Andre Przywara
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

map_resources is the last initialization step needed before the first
VCPU is run. At that stage the code stores the MMIO base addresses used.
Also it registers the respective register frames with the MMIO framework.

This is based on Linux commit cbae53e663ea, written by Eric Auger.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
Acked-by: Julien Grall <julien.grall@arm.com>
---
 xen/arch/arm/vgic/vgic-v2.c | 66 +++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic/vgic.h    |  1 +
 2 files changed, 67 insertions(+)

diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c
index ce77e58857..5516a8534f 100644
--- a/xen/arch/arm/vgic/vgic-v2.c
+++ b/xen/arch/arm/vgic/vgic-v2.c
@@ -235,6 +235,72 @@ void vgic_v2_enable(struct vcpu *vcpu)
     gic_hw_ops->update_hcr_status(GICH_HCR_EN, true);
 }
 
+int vgic_v2_map_resources(struct domain *d)
+{
+    struct vgic_dist *dist = &d->arch.vgic;
+    paddr_t cbase, csize;
+    paddr_t vbase;
+    int ret;
+
+    /*
+     * The hardware domain gets the hardware address.
+     * Guests get the virtual platform layout.
+     */
+    if ( is_hardware_domain(d) )
+    {
+        d->arch.vgic.vgic_dist_base = gic_v2_hw_data.dbase;
+        /*
+         * For the hardware domain, we always map the whole HW CPU
+         * interface region in order to match the device tree (the "reg"
+         * properties is copied as it is).
+         * Note that we assume the size of the CPU interface is always
+         * aligned to PAGE_SIZE.
+         */
+        cbase = gic_v2_hw_data.cbase; /* was: dist->vgic_cpu_base */
+        csize = gic_v2_hw_data.csize;
+        vbase = gic_v2_hw_data.vbase; /* was: kvm_vgic_global_state.vcpu_base */
+    }
+    else
+    {
+        d->arch.vgic.vgic_dist_base = GUEST_GICD_BASE;
+        /*
+         * The CPU interface exposed to the guest is always 8kB. We may
+         * need to add an offset to the virtual CPU interface base
+         * address when in the GIC is aliased to get a 8kB contiguous
+         * region.
+         */
+        BUILD_BUG_ON(GUEST_GICC_SIZE != SZ_8K);
+        cbase = GUEST_GICC_BASE;
+        csize = GUEST_GICC_SIZE;
+        vbase = gic_v2_hw_data.vbase + gic_v2_hw_data.aliased_offset;
+    }
+
+
+    ret = vgic_register_dist_iodev(d, gaddr_to_gfn(dist->vgic_dist_base),
+                                   VGIC_V2);
+    if ( ret )
+    {
+        gdprintk(XENLOG_ERR, "Unable to register VGIC MMIO regions\n");
+        return ret;
+    }
+
+    /*
+     * Map the gic virtual cpu interface in the gic cpu interface
+     * region of the guest.
+     */
+    ret = map_mmio_regions(d, gaddr_to_gfn(cbase), csize / PAGE_SIZE,
+                           maddr_to_mfn(vbase));
+    if ( ret )
+    {
+        gdprintk(XENLOG_ERR, "Unable to remap VGIC CPU to VCPU\n");
+        return ret;
+    }
+
+    dist->ready = true;
+
+        return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
index 112952fbf9..e8e407adbe 100644
--- a/xen/arch/arm/vgic/vgic.h
+++ b/xen/arch/arm/vgic/vgic.h
@@ -67,6 +67,7 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu);
 void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_set_underflow(struct vcpu *vcpu);
 void vgic_v2_enable(struct vcpu *vcpu);
+int vgic_v2_map_resources(struct domain *d);
 int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
                              enum vgic_type);
 
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 38/39] ARM: new VGIC: Allocate two pages for struct vcpu
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (36 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 37/39] ARM: new VGIC: vgic-init: implement map_resources Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  8:11   ` Julien Grall
  2018-03-21 16:32 ` [PATCH v3 39/39] ARM: VGIC: wire new VGIC(-v2) files into Xen build system Andre Przywara
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel, Andre Przywara

At the moment we allocate exactly one page for struct vcpu on ARM, also
have a check in place to prevent it growing beyond 4KB.
As the struct includes the state of all 32 private (per-VCPU) interrupts,
we are at 3840 bytes on arm64 at the moment already. Growing the per-IRQ
VGIC structure even slightly makes the VCPU quickly exceed the 4K limit.
The new VGIC will need more space per virtual IRQ. I spent a few hours
trying to trim this down, but couldn't get it below 4KB, even with the
nasty hacks piling up to save some bytes here and there.
It turns out that beyond efficiency, maybe, there is no real technical
reason this struct has to fit in one page, so lifting the limit to two
pages seems like the most pragmatic solution.
Restrict this to compiling with the new VGIC and for ARM64 only.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- rework alloc_vcpu_struct() to avoid nasty #ifdef

Changelog v1 ... v2:
- confine change to new VGIC and ARM64 only

 xen/arch/arm/domain.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 9688e62f78..23bda3f7db 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -505,19 +505,36 @@ void dump_pageframe_info(struct domain *d)
 
 }
 
+/*
+ * The new VGIC has a bigger per-IRQ structure, so we need more than one
+ * page on ARM64. Cowardly increase the limit in this case.
+ */
+#if defined(CONFIG_NEW_VGIC) && defined(CONFIG_ARM_64)
+#define PAGES_PER_VCPU  2
+#else
+#define PAGES_PER_VCPU  1
+#endif
+
 struct vcpu *alloc_vcpu_struct(void)
 {
     struct vcpu *v;
-    BUILD_BUG_ON(sizeof(*v) > PAGE_SIZE);
-    v = alloc_xenheap_pages(0, 0);
+
+    BUILD_BUG_ON(sizeof(*v) > PAGES_PER_VCPU * PAGE_SIZE);
+    v = alloc_xenheap_pages(get_order_from_pages(PAGES_PER_VCPU), 0);
     if ( v != NULL )
-        clear_page(v);
+    {
+        unsigned int i;
+
+        for ( i = 0; i < PAGES_PER_VCPU; i++ )
+            clear_page((void *)v + i * PAGE_SIZE);
+    }
+
     return v;
 }
 
 void free_vcpu_struct(struct vcpu *v)
 {
-    free_xenheap_page(v);
+    free_xenheap_pages(v, get_order_from_pages(PAGES_PER_VCPU));
 }
 
 int vcpu_initialise(struct vcpu *v)
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* [PATCH v3 39/39] ARM: VGIC: wire new VGIC(-v2) files into Xen build system
  2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
                   ` (37 preceding siblings ...)
  2018-03-21 16:32 ` [PATCH v3 38/39] ARM: new VGIC: Allocate two pages for struct vcpu Andre Przywara
@ 2018-03-21 16:32 ` Andre Przywara
  2018-03-22  8:16   ` Julien Grall
  38 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-21 16:32 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: Wei Liu, George Dunlap, Andrew Cooper, Ian Jackson,
	Andre Przywara, Tim Deegan, Jan Beulich, xen-devel

Now that we have both the old VGIC prepared to cope with a sibling and
the code for the new VGIC in place, lets add a Kconfig option to enable
the new code and wire it into the Xen build system.
This will add a compile time option to use either the "old" or the "new"
VGIC.
In the moment this is restricted to a vGIC-v2. To make the build system
happy, we provide a temporary dummy implementation of
vgic_v3_setup_hw() to allow building for now.

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Changelog v2 ... v3:
- fix indentation of Kconfig entry
- select NEEDS_LIST_SORT
- drop unconditional list_sort.o inclusion

Changelog v1 ... v2:
- add Kconfig help text
- use separate Makefile in vgic/ directory
- protect compilation without GICV3 support
- always include list_sort() in build

 xen/arch/arm/Kconfig       | 18 +++++++++++++++++-
 xen/arch/arm/Makefile      |  5 ++++-
 xen/arch/arm/vgic/Makefile |  5 +++++
 xen/arch/arm/vgic/vgic.c   | 10 ++++++++++
 4 files changed, 36 insertions(+), 2 deletions(-)
 create mode 100644 xen/arch/arm/vgic/Makefile

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 2782ee6589..8174c0c635 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -48,7 +48,23 @@ config HAS_GICV3
 config HAS_ITS
         bool
         prompt "GICv3 ITS MSI controller support" if EXPERT = "y"
-        depends on HAS_GICV3
+        depends on HAS_GICV3 && !NEW_VGIC
+
+config NEW_VGIC
+	bool
+	prompt "Use new VGIC implementation"
+	select NEEDS_LIST_SORT
+	---help---
+
+	This is an alternative implementation of the ARM GIC interrupt
+	controller emulation, based on the Linux/KVM VGIC. It has a better
+	design and fixes many shortcomings of the existing GIC emulation in
+	Xen. It will eventually replace the existing/old VGIC.
+	However at the moment it lacks support for Dom0 using the ITS for
+	using MSIs.
+	Say Y if you want to help testing this new code or if you experience
+	problems with the standard emulation.
+	At the moment this implementation is not security supported.
 
 config SBSA_VUART_CONSOLE
 	bool "Emulated SBSA UART console support"
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 41d7366527..a9533b107e 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -16,7 +16,6 @@ obj-y += domain_build.o
 obj-y += domctl.o
 obj-$(EARLY_PRINTK) += early_printk.o
 obj-y += gic.o
-obj-y += gic-vgic.o
 obj-y += gic-v2.o
 obj-$(CONFIG_HAS_GICV3) += gic-v3.o
 obj-$(CONFIG_HAS_ITS) += gic-v3-its.o
@@ -47,10 +46,14 @@ obj-y += sysctl.o
 obj-y += time.o
 obj-y += traps.o
 obj-y += vcpreg.o
+subdir-$(CONFIG_NEW_VGIC) += vgic
+ifneq ($(CONFIG_NEW_VGIC),y)
+obj-y += gic-vgic.o
 obj-y += vgic.o
 obj-y += vgic-v2.o
 obj-$(CONFIG_HAS_GICV3) += vgic-v3.o
 obj-$(CONFIG_HAS_ITS) += vgic-v3-its.o
+endif
 obj-y += vm_event.o
 obj-y += vtimer.o
 obj-$(CONFIG_SBSA_VUART_CONSOLE) += vpl011.o
diff --git a/xen/arch/arm/vgic/Makefile b/xen/arch/arm/vgic/Makefile
new file mode 100644
index 0000000000..806826948e
--- /dev/null
+++ b/xen/arch/arm/vgic/Makefile
@@ -0,0 +1,5 @@
+obj-y += vgic.o
+obj-y += vgic-v2.o
+obj-y += vgic-mmio.o
+obj-y += vgic-mmio-v2.o
+obj-y += vgic-init.o
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 131358a5a1..22c70ff7cd 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -981,6 +981,16 @@ unsigned int vgic_max_vcpus(const struct domain *d)
     return min_t(unsigned int, MAX_VIRT_CPUS, vgic_vcpu_limit);
 }
 
+#ifdef CONFIG_HAS_GICV3
+void vgic_v3_setup_hw(paddr_t dbase,
+                      unsigned int nr_rdist_regions,
+                      const struct rdist_region *regions,
+                      unsigned int intid_bits)
+{
+    /* Dummy implementation to allow building without actual vGICv3 support. */
+}
+#endif
+
 /*
  * Local variables:
  * mode: C
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 11/39] Add list_sort() routine from Linux
  2018-03-21 16:32 ` [PATCH v3 11/39] Add list_sort() routine from Linux Andre Przywara
@ 2018-03-21 17:01   ` Jan Beulich
  2018-03-22  2:14   ` Julien Grall
  1 sibling, 0 replies; 122+ messages in thread
From: Jan Beulich @ 2018-03-21 17:01 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Stefano Stabellini, Wei Liu, George Dunlap, Andrew Cooper,
	Ian Jackson, Tim Deegan, Julien Grall, xen-devel

>>> On 21.03.18 at 17:32, <andre.przywara@linaro.org> wrote:
> --- a/xen/common/Kconfig
> +++ b/xen/common/Kconfig
> @@ -44,6 +44,9 @@ config HAS_GDBSX
>  config HAS_IOPORTS
>  	bool
>  
> +config NEEDS_LIST_SORT
> +        bool
> +
>  config HAS_BUILD_ID
>  	string
>  	option env="XEN_HAS_BUILD_ID"

Please look at surrounding code when adding new entries: Tabs are
used for indentation here.

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version
  2018-03-21 16:31 ` [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version Andre Przywara
@ 2018-03-22  1:39   ` Julien Grall
  2018-03-26 20:08   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  1:39 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:31 PM, Andre Przywara wrote:
> The enum gic_version at the moment just contains GIC_V2 and GIC_V3,
> where GIC_V2 happens to map to 0. So without having initialised a
> variable of that type, we will read back GIC_V2 (when allocated with zeroing
> the memory).
> To prevent ambiguities and to give an explicitly uninitialised state, add
> a new first member: GIC_INVALID. Also make it obvious that this has a
> "0" encoding.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

> ---
>   xen/include/asm-arm/gic.h | 1 +
>   1 file changed, 1 insertion(+)
> 
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 565b0875ca..3079387e06 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -227,6 +227,7 @@ struct gic_lr {
>   };
>   
>   enum gic_version {
> +    GIC_INVALID = 0,    /* the default until explicitly set up */
>       GIC_V2,
>       GIC_V3,
>   };
> 

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 03/39] ARM: GIC: Allow tweaking the active and pending state of an IRQ
  2018-03-21 16:31 ` [PATCH v3 03/39] ARM: GIC: Allow tweaking the active and pending state of an IRQ Andre Przywara
@ 2018-03-22  1:51   ` Julien Grall
  2018-03-22 11:11     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Julien Grall @ 2018-03-22  1:51 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:31 PM, Andre Przywara wrote:
> When playing around with hardware mapped, level triggered virtual IRQs,
> there is the need to explicitly set the active or pending state of an
> interrupt at some point.
> To prepare the GIC for that, we introduce a set_active_state() and a
> set_pending_state() function to let the VGIC manipulate the state of
> an associated hardware IRQ.
> This takes care of properly setting the _IRQ_INPROGRESS bit.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> Changelog v2 ... v3:
> - rework setting _IRQ_INPROGRESS bit:
>    - no change when changing active state
>    - unconditional set/clear on changing pending state
> - drop introduction of gicv[23]_peek_irq() (only needed in the next patch now)
> 
> Changelog v1 ... v2:
> - properly set _IRQ_INPROGRESS bit
> - add gicv[23]_peek_irq() (pulled in from later patch)
> - move wrappers functions into gic.h
> 
>   xen/arch/arm/gic-v2.c     | 36 ++++++++++++++++++++++++++++++++++++
>   xen/arch/arm/gic-v3.c     | 32 ++++++++++++++++++++++++++++++++
>   xen/include/asm-arm/gic.h | 24 ++++++++++++++++++++++++
>   3 files changed, 92 insertions(+)
> 
> diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
> index aa0fc6c1a1..d1f1578c05 100644
> --- a/xen/arch/arm/gic-v2.c
> +++ b/xen/arch/arm/gic-v2.c
> @@ -243,6 +243,40 @@ static void gicv2_poke_irq(struct irq_desc *irqd, uint32_t offset)
>       writel_gicd(1U << (irqd->irq % 32), offset + (irqd->irq / 32) * 4);
>   }
>   
> +static void gicv2_set_active_state(struct irq_desc *irqd, bool active)
> +{
> +    ASSERT(spin_is_locked(&irqd->lock));
> +
> +    if ( active )
> +    {
> +        if ( test_bit(_IRQ_GUEST, &irqd->status) )

I don't understand why you only set/clear INPROGRESS bit for interrupt 
routed to guest. This will matter when releasing interrupt used by Xen 
(see release_irq).

Note that I don't expect this helper to be call on Xen IRQ, but I think 
we should make

Other than same remark on GICv3 code, the pending implementation looks 
good to me now.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly
  2018-03-21 16:32 ` [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly Andre Przywara
@ 2018-03-22  1:58   ` Julien Grall
  2018-03-26 20:28   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  1:58 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> The ARM Generic Timer uses a level-sensitive interrupt semantic. We
> easily catch when the line goes high, as this triggers the hardware IRQ.
> However we also have to keep track of when the line lowers, as the
> emulation depends on it: Upon entering the guest, the new VGIC will
> *clear* the virtual interrupt line, so it needs to re-sample the actual
> state after returning from the guest.
> So we have to sync the state of the interrupt condition at certain
> points to catch when the line goes low and we can remove the vtimer vIRQ
> from the vGIC (and the LR).
> The VGIC in Xen so far only implemented edge triggered vIRQs, really, so
> we need to add new functionality to re-sample the interrupt state.
> Do this only when the new VGIC is in use.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-21 16:32 ` [PATCH v3 06/39] ARM: evtchn: " Andre Przywara
@ 2018-03-22  2:08   ` Julien Grall
  2018-03-26 20:08   ` Stefano Stabellini
  2018-03-28  0:01   ` Stefano Stabellini
  2 siblings, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  2:08 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel



On 03/21/2018 04:32 PM, Andre Przywara wrote:
> The event channel IRQ has level triggered semantics, however the current
> VGIC treats everything as edge triggered.
> To correctly process those IRQs, we have to lower the (virtual) IRQ line
> at some point in time, depending on whether ther interrupt condition

NIT: s/ther/the/

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 09/39] ARM: new VGIC: Add accessor to new struct vgic_irq instance
  2018-03-21 16:32 ` [PATCH v3 09/39] ARM: new VGIC: Add accessor to new struct vgic_irq instance Andre Przywara
@ 2018-03-22  2:11   ` Julien Grall
  2018-03-26 20:46     ` Stefano Stabellini
  0 siblings, 1 reply; 122+ messages in thread
From: Julien Grall @ 2018-03-22  2:11 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> The new VGIC implementation centers around a struct vgic_irq instance
> per virtual IRQ.
> Provide a function to retrieve the right instance for a given IRQ
> number and (in case of private interrupts) the right VCPU.
> This also includes the corresponding put function, which does nothing
> for private interrupts and SPIs, but handles the ref-counting for LPIs.
> 
> This is based on Linux commit 64a959d66e47, written by Christoffer Dall.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> Changelog v2 ... v3:
> - extend comments to note preliminary nature of vgic_get_lpi()

Thank you for the update.

> 
> Changelog v1 ... v2:
> - reorder header file inclusion
> 
>   xen/arch/arm/vgic/vgic.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++
>   xen/arch/arm/vgic/vgic.h |  41 +++++++++++++++
>   2 files changed, 175 insertions(+)
>   create mode 100644 xen/arch/arm/vgic/vgic.c
>   create mode 100644 xen/arch/arm/vgic/vgic.h
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> new file mode 100644
> index 0000000000..a818e382b1
> --- /dev/null
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -0,0 +1,134 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
> + *
> + * 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/sched.h>
> +#include <asm/bug.h>
> +#include <asm/new_vgic.h>
> +
> +#include "vgic.h"
> +
> +/*
> + * Iterate over the VM's list of mapped LPIs to find the one with a
> + * matching interrupt ID and return a reference to the IRQ structure.
> + *
> + * TODO: This is more documentation of how it should be done. A list is
> + * not a good data structure for Dom0's LPIs, it merely serves as an
> + * example here how to properly do the locking, allocation and refcounting.
> + * So lpi_list_head should be replaced with something more appropriate.
> + */
> +static struct vgic_irq *vgic_get_lpi(struct domain *d, u32 intid)

It looks like I forgot to mention it on previous version. Please replace 
u32 with uint32_t.

[...]

> +struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
> +                              u32 intid)

Here too.

> +{
> +    /* SGIs and PPIs */
> +    if ( intid <= VGIC_MAX_PRIVATE )
> +        return &vcpu->arch.vgic.private_irqs[intid];
> +
> +    /* SPIs */
> +    if ( intid <= VGIC_MAX_SPI )
> +        return &d->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> +
> +    /* LPIs */
> +    if ( intid >= VGIC_MIN_LPI )
> +        return vgic_get_lpi(d, intid);
> +
> +    ASSERT_UNREACHABLE();
> +
> +    return NULL;
> +}
> +

[...]

> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> new file mode 100644
> index 0000000000..a3befd386b
> --- /dev/null
> +++ b/xen/arch/arm/vgic/vgic.h

[...]

> +struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
> +                              u32 intid);

And here too.

With that:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 11/39] Add list_sort() routine from Linux
  2018-03-21 16:32 ` [PATCH v3 11/39] Add list_sort() routine from Linux Andre Przywara
  2018-03-21 17:01   ` Jan Beulich
@ 2018-03-22  2:14   ` Julien Grall
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  2:14 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: Wei Liu, George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich, xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> This pulls in Linux' list_sort.c, which is a merge sort implementation

s/Linux'/Linux's/ ?

> for linked lists. Apart from adding a full featured license header and
> adjusting the #include file, nothing has been changed in this code.
> Define a promptless Kconfig which configurations can select when they
> need this code and add it to the Makefile.
> 
> This is from Linux' lib/list_sort.c, as of commit e327fd7c8667
> ("lib: add module support to linked list sorting tests").
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

With the NIT above and Jan's comment addressed:

Acked-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework
  2018-03-21 16:32 ` [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework Andre Przywara
@ 2018-03-22  2:16   ` Julien Grall
  2018-03-26 21:30   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  2:16 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> Implement the framework for syncing IRQs between our emulation and the
> list registers, which represent the guest's view of IRQs.
> This is done in vgic_sync_from_lrs() and vgic_sync_to_lrs(), which
> get called on guest entry and exit, respectively.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> This is based on Linux commit 0919e84c0fc1, written by Marc Zyngier.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend
  2018-03-21 16:32 ` [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend Andre Przywara
@ 2018-03-22  3:48   ` Julien Grall
  2018-03-22 11:04     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Julien Grall @ 2018-03-22  3:48 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> +        /*
> +         * If a hardware mapped IRQ has been handled for good, we need to
> +         * clear the _IRQ_INPROGRESS bit to allow handling of new IRQs.
> +         */
> +        if ( irq->hw && !lr_val.active && !lr_val.pending )
> +        {
> +            struct irq_desc *irqd = irq_to_desc(irq->hwintid);
> +
> +            clear_bit(_IRQ_INPROGRESS, &irqd->status);

I realize the current vGIC is doing exactly the same thing. But this is 
racy.

Imagine the interrupt is firing on another pCPU (I wasn't able to rule 
out this even when the interrupt is following the vCPU), that pCPU may 
set _IRQ_INPROGRESS before this is cleared here.

So you would end up clearing _IRQ_INPROGRESS here, making the desc state 
inconsistent and would affect the removal of the IRQ from a guest (see 
gic_remove_irq_from_guest).

I am not entirely sure how to fix this because taking the desc->lock 
would not be enough. Indeed you may end up to clear right after the flag 
was set in do_IRQ.

Because the race is already there in the current vGIC and only affecting 
release IRQ, I guess I would be ok to keep like that for now. Can you 
add a TODO?

> +        }
> +
> +        /* Always preserve the active bit */
> +        irq->active = lr_val.active;
> +
> +        /* Edge is the only case where we preserve the pending bit */
> +        if ( irq->config == VGIC_CONFIG_EDGE && lr_val.pending )
> +        {
> +            irq->pending_latch = true;
> +
> +            if ( vgic_irq_is_sgi(intid) )
> +                irq->source |= (1U << lr_val.virt.source);
> +        }
> +
> +        /* Clear soft pending state when level irqs have been acked. */
> +        if ( irq->config == VGIC_CONFIG_LEVEL && !lr_val.pending )
> +            irq->pending_latch = false;
> +
> +        /*
> +         * Level-triggered mapped IRQs are special because we only
> +         * observe rising edges as input to the VGIC.
> +         *
> +         * If the guest never acked the interrupt we have to sample
> +         * the physical line and set the line level, because the
> +         * device state could have changed or we simply need to
> +         * process the still pending interrupt later.
> +         *
> +         * If this causes us to lower the level, we have to also clear
> +         * the physical active state, since we will otherwise never be
> +         * told when the interrupt becomes asserted again.
> +         */
> +        if ( vgic_irq_is_mapped_level(irq) && lr_val.pending )
> +        {
> +            struct irq_desc *irqd;
> +
> +            ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
> +
> +            irqd = irq_to_desc(irq->hwintid);
> +            irq->line_level = gic_read_pending_state(irqd);
> +
> +            if ( !irq->line_level )
> +                gic_set_active_state(irqd, false);

Sorry, I didn't notice it before. gic_set_active_state expect the 
desc->lock to be taken. But I can't see the code here to do that.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq
  2018-03-21 16:32 ` [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq Andre Przywara
@ 2018-03-22  3:52   ` Julien Grall
  2018-03-22 11:15     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Julien Grall @ 2018-03-22  3:52 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> Tell Xen whether a particular VCPU has an IRQ that needs handling
> in the guest. This is used to decide whether a VCPU is runnable or
> if a hypercall should be preempted to let the guest handle the IRQ.
> 
> This is based on Linux commit 90eee56c5f90, written by Eric Auger.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> Changelog v2 ... v3:
> - adjust vgic_vcpu_pending_irq() to return integers, not false/true

I would have preferred to have the return switch to bool instead. I 
guess this can be done on a follow-up. With one comment below:

Reviewed-by: Julien Grall <julien.grall@arm.com>

> 
> Changelog v1 ... v2:
> - adjust to new vgic_vcpu_pending_irq() prototype, drop wrapper
> 
>   xen/arch/arm/vgic/vgic.c | 37 +++++++++++++++++++++++++++++++++++++
>   1 file changed, 37 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 2fa595f4f7..925cda4580 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -647,6 +647,43 @@ void vgic_sync_to_lrs(void)
>       gic_hw_ops->update_hcr_status(GICH_HCR_EN, 1);
>   }
>   
> +/**
> + * vgic_vcpu_pending_irq() - determine if interrupts need to be injected
> + * @vcpu: The vCPU on which to check for interrupts.
> + *
> + * Checks whether there is an interrupt on the given VCPU which needs
> + * handling in the guest. This requires at least one IRQ to be pending
> + * and enabled.
> + *
> + * Returns: 1 if the guest should run to handle interrupts, 0 otherwise.

NIT: Because of "ret = irq_is_pending(irq) && irq->enabled", you will 
return a non-zero value if the guest should run to handle interrupts.

> + */
> +int vgic_vcpu_pending_irq(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +    struct vgic_irq *irq;
> +    unsigned long flags;
> +    int ret = 0;
> +
> +    if ( !vcpu->domain->arch.vgic.enabled )
> +        return 0;
> +
> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
> +
> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
> +    {
> +        spin_lock(&irq->irq_lock);
> +        ret = irq_is_pending(irq) && irq->enabled;
> +        spin_unlock(&irq->irq_lock);
> +
> +        if ( ret )
> +            break;
> +    }
> +
> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
> +
> +    return ret;
> +}
> +
>   /*
>    * Local variables:
>    * mode: C
> 

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers
  2018-03-21 16:32 ` [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers Andre Przywara
@ 2018-03-22  7:33   ` Julien Grall
  2018-03-27 20:38   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  7:33 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> Those three registers are v2 emulation specific, so their implementation
> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> as their implementation is pretty simple.
> We choose to piggy-back on the existing KVM identification registers,
> but use a different variant (major revision).
> When the guest enables the distributor, we kick all VCPUs to get
> potentially pending interrupts serviced.
> 
> This is based on Linux commit 2b0cda878965, written by Marc Zyngier.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler
  2018-03-21 16:32 ` [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler Andre Przywara
@ 2018-03-22  7:54   ` Julien Grall
  2018-03-27 22:23   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  7:54 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> Triggering an IPI via this register is v2 specific, so the
> implementation lives entirely in vgic-mmio-v2.c.
> 
> This is based on Linux commit 55cc01fb9004, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,

> ---
> Changelog v2 ... v3:
> - fix target mask calculation
> 
> Changelog v1 ... v2:
> - remove stray rebase artefact
> 
>   xen/arch/arm/vgic/vgic-mmio-v2.c | 45 +++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 44 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index b333de9ed7..9ef80608c1 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -81,6 +81,49 @@ static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
>       }
>   }
>   
> +static void vgic_mmio_write_sgir(struct vcpu *source_vcpu,
> +                                 paddr_t addr, unsigned int len,
> +                                 unsigned long val)
> +{
> +    struct domain *d = source_vcpu->domain;
> +    unsigned int nr_vcpus = d->max_vcpus;
> +    unsigned int intid = val & GICD_SGI_INTID_MASK;
> +    unsigned long targets = (val & GICD_SGI_TARGET_MASK) >>
> +                            GICD_SGI_TARGET_SHIFT;
> +    unsigned int vcpu_id;
> +
> +    switch ( val & GICD_SGI_TARGET_LIST_MASK )
> +    {
> +    case GICD_SGI_TARGET_LIST:                    /* as specified by targets */
> +        targets &= GENMASK(nr_vcpus - 1, 0);      /* limit to existing VCPUs */
> +        break;
> +    case GICD_SGI_TARGET_OTHERS:
> +        targets = GENMASK(nr_vcpus - 1, 0);       /* all, ...   */
> +        targets &= ~(1U << source_vcpu->vcpu_id); /*   but self */
> +        break;
> +    case GICD_SGI_TARGET_SELF:                    /* this very vCPU only */
> +        targets = (1U << source_vcpu->vcpu_id);
> +        break;
> +    case 0x3:                                     /* reserved */
> +        return;
> +    }
> +
> +    for_each_set_bit( vcpu_id, &targets, 8 )
> +    {
> +        struct vcpu *vcpu = d->vcpu[vcpu_id];
> +        struct vgic_irq *irq = vgic_get_irq(d, vcpu, intid);
> +        unsigned long flags;
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        irq->pending_latch = true;
> +        irq->source |= 1U << source_vcpu->vcpu_id;
> +
> +        vgic_queue_irq_unlock(d, irq, flags);
> +        vgic_put_irq(d, irq);
> +    }
> +}
> +
>   static unsigned long vgic_mmio_read_target(struct vcpu *vcpu,
>                                              paddr_t addr, unsigned int len)
>   {
> @@ -173,7 +216,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>           vgic_mmio_read_config, vgic_mmio_write_config, 2,
>           VGIC_ACCESS_32bit),
>       REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
> +        vgic_mmio_read_raz, vgic_mmio_write_sgir, 4,
>           VGIC_ACCESS_32bit),
>       REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
>           vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> 

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC
  2018-03-21 16:32 ` [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC Andre Przywara
@ 2018-03-22  8:00   ` Julien Grall
  2018-03-22 11:18     ` Andre Przywara
  2018-03-27 22:50     ` Stefano Stabellini
  0 siblings, 2 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  8:00 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> This patch implements the function which is called by Xen when it wants
> to register the virtual GIC.
> This also implements vgic_max_vcpus() for the new VGIC, which reports
> back the maximum number of VCPUs a certain GIC model supports. Similar
> to the counterpart in the "old" VGIC, we return some maximum value if
> the VGIC has not been initialised yet.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Thank you for the update. We will have to remove the GIC_INVALID case 
once Andrew's series is merged. If his series is merged before yours, it 
would not be an issue as that case should never be hit.

So:

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init
  2018-03-21 16:32 ` [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init Andre Przywara
@ 2018-03-22  8:01   ` Julien Grall
  2018-03-27 23:16   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22  8:01 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> This patch allocates and initializes the data structures used to model
> the vgic distributor and virtual cpu interfaces. At that stage the
> number of IRQs and number of virtual CPUs is frozen.
> Implement the various functions that the Xen arch code is expecting to
> call during domain and VCPU setup to initialize the VGIC.
> Their prototypes are already in existing header files.
> 
> This is based on Linux commit ad275b8bb1e6, written by Eric Auger.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Reviewed-by: Julien Grall <julien.grall@arm.com>

Cheers,

> ---
> Changelog v2 ... v3:
> - move ROUNDUP(nr_spis) call before boundary check
> 
> Changelog v1 ... v2:
> - remove stray kvm_ prefix in comment
> - use unsigned int
> - ROUNDUP number of SPIs
> - fix indentation
> 
>   xen/arch/arm/vgic/vgic-init.c | 201 ++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 201 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
> index d091c92ed0..bfd3d09edb 100644
> --- a/xen/arch/arm/vgic/vgic-init.c
> +++ b/xen/arch/arm/vgic/vgic-init.c
> @@ -15,11 +15,83 @@
>    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>    */
>   
> +#include <xen/lib.h>
>   #include <xen/sched.h>
>   #include <asm/new_vgic.h>
>   
>   #include "vgic.h"
>   
> +/*
> + * Initialization rules: there are multiple stages to the vgic
> + * initialization, both for the distributor and the CPU interfaces.  The basic
> + * idea is that even though the VGIC is not functional or not requested from
> + * user space, the critical path of the run loop can still call VGIC functions
> + * that just won't do anything, without them having to check additional
> + * initialization flags to ensure they don't look at uninitialized data
> + * structures.
> + *
> + * Distributor:
> + *
> + * - vgic_early_init(): initialization of static data that doesn't
> + *   depend on any sizing information or emulation type. No allocation
> + *   is allowed there.
> + *
> + * - vgic_init(): allocation and initialization of the generic data
> + *   structures that depend on sizing information (number of CPUs,
> + *   number of interrupts). Also initializes the vcpu specific data
> + *   structures. Can be executed lazily for GICv2.
> + *
> + * CPU Interface:
> + *
> + * - vgic_vcpu_early_init(): initialization of static data that
> + *   doesn't depend on any sizing information or emulation type. No
> + *   allocation is allowed there.
> + */
> +
> +/**
> + * vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
> + * @vcpu: The VCPU whose VGIC data structures whould be initialized
> + *
> + * Only do initialization, but do not actually enable the VGIC CPU interface
> + * yet.
> + */
> +static void vgic_vcpu_early_init(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +    unsigned int i;
> +
> +    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +    spin_lock_init(&vgic_cpu->ap_list_lock);
> +
> +    /*
> +     * Enable and configure all SGIs to be edge-triggered and
> +     * configure all PPIs as level-triggered.
> +     */
> +    for ( i = 0; i < VGIC_NR_PRIVATE_IRQS; i++ )
> +    {
> +        struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
> +
> +        INIT_LIST_HEAD(&irq->ap_list);
> +        spin_lock_init(&irq->irq_lock);
> +        irq->intid = i;
> +        irq->vcpu = NULL;
> +        irq->target_vcpu = vcpu;
> +        irq->targets = 1U << vcpu->vcpu_id;
> +        atomic_set(&irq->refcount, 0);
> +        if ( vgic_irq_is_sgi(i) )
> +        {
> +            /* SGIs */
> +            irq->enabled = 1;
> +            irq->config = VGIC_CONFIG_EDGE;
> +        }
> +        else
> +        {
> +            /* PPIs */
> +            irq->config = VGIC_CONFIG_LEVEL;
> +        }
> +    }
> +}
> +
>   /* CREATION */
>   
>   /**
> @@ -50,6 +122,135 @@ int domain_vgic_register(struct domain *d, int *mmio_count)
>       return 0;
>   }
>   
> +/* INIT/DESTROY */
> +
> +/**
> + * domain_vgic_init: initialize the dist data structures
> + * @d: domain pointer
> + * @nr_spis: number of SPIs
> + */
> +int domain_vgic_init(struct domain *d, unsigned int nr_spis)
> +{
> +    struct vgic_dist *dist = &d->arch.vgic;
> +    unsigned int i;
> +    int ret;
> +
> +    /* The number of SPIs must be a multiple of 32 per the GIC spec. */
> +    nr_spis = ROUNDUP(nr_spis, 32);
> +
> +    /* Limit the number of virtual SPIs supported to (1020 - 32) = 988  */
> +    if ( nr_spis > (1020 - NR_LOCAL_IRQS) )
> +        return -EINVAL;
> +
> +    dist->nr_spis = nr_spis;
> +    dist->spis = xzalloc_array(struct vgic_irq, nr_spis);
> +    if ( !dist->spis )
> +        return  -ENOMEM;
> +
> +    /*
> +     * In the following code we do not take the irq struct lock since
> +     * no other action on irq structs can happen while the VGIC is
> +     * not initialized yet:
> +     * If someone wants to inject an interrupt or does a MMIO access, we
> +     * require prior initialization in case of a virtual GICv3 or trigger
> +     * initialization when using a virtual GICv2.
> +     */
> +    for ( i = 0; i < nr_spis; i++ )
> +    {
> +        struct vgic_irq *irq = &dist->spis[i];
> +
> +        irq->intid = i + VGIC_NR_PRIVATE_IRQS;
> +        INIT_LIST_HEAD(&irq->ap_list);
> +        spin_lock_init(&irq->irq_lock);
> +        irq->vcpu = NULL;
> +        irq->target_vcpu = NULL;
> +        atomic_set(&irq->refcount, 0);
> +        if ( dist->version == GIC_V2 )
> +            irq->targets = 0;
> +        else
> +            irq->mpidr = 0;
> +    }
> +
> +    INIT_LIST_HEAD(&dist->lpi_list_head);
> +    spin_lock_init(&dist->lpi_list_lock);
> +
> +    if ( dist->version == GIC_V2 )
> +        ret = vgic_v2_map_resources(d);
> +    else
> +        ret = -ENXIO;
> +
> +    if ( ret )
> +        return ret;
> +
> +    /* allocated_irqs() is used by Xen to find available vIRQs */
> +    d->arch.vgic.allocated_irqs =
> +        xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d)));
> +    if ( !d->arch.vgic.allocated_irqs )
> +        return -ENOMEM;
> +
> +    /* vIRQ0-15 (SGIs) are reserved */
> +    for ( i = 0; i < NR_GIC_SGI; i++ )
> +        set_bit(i, d->arch.vgic.allocated_irqs);
> +
> +    return 0;
> +}
> +
> +/**
> + * vcpu_vgic_init() - Register VCPU-specific KVM iodevs
> + * was: kvm_vgic_vcpu_init()
> + * Xen: adding vgic_vx_enable() call
> + * @vcpu: pointer to the VCPU being created and initialized
> + */
> +int vcpu_vgic_init(struct vcpu *vcpu)
> +{
> +    int ret = 0;
> +
> +    vgic_vcpu_early_init(vcpu);
> +
> +    if ( gic_hw_version() == GIC_V2 )
> +        vgic_v2_enable(vcpu);
> +    else
> +        ret = -ENXIO;
> +
> +    return ret;
> +}
> +
> +void domain_vgic_free(struct domain *d)
> +{
> +    struct vgic_dist *dist = &d->arch.vgic;
> +        int i, ret;
> +
> +    for ( i = 0; i < dist->nr_spis; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(d, NULL, 32 + i);
> +
> +        if ( !irq->hw )
> +            continue;
> +
> +        ret = release_guest_irq(d, irq->hwintid);
> +        if ( ret )
> +            dprintk(XENLOG_G_WARNING,
> +                    "d%u: Failed to release virq %u ret = %d\n",
> +                    d->domain_id, 32 + i, ret);
> +    }
> +
> +    dist->ready = false;
> +    dist->initialized = false;
> +
> +    xfree(dist->spis);
> +    xfree(dist->allocated_irqs);
> +    dist->nr_spis = 0;
> +}
> +
> +int vcpu_vgic_free(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +
> +    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +
> +    return 0;
> +}
> +
>   /*
>    * Local variables:
>    * mode: C
> 

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 38/39] ARM: new VGIC: Allocate two pages for struct vcpu
  2018-03-21 16:32 ` [PATCH v3 38/39] ARM: new VGIC: Allocate two pages for struct vcpu Andre Przywara
@ 2018-03-22  8:11   ` Julien Grall
  2018-03-27 23:07     ` Stefano Stabellini
  0 siblings, 1 reply; 122+ messages in thread
From: Julien Grall @ 2018-03-22  8:11 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> At the moment we allocate exactly one page for struct vcpu on ARM, also
> have a check in place to prevent it growing beyond 4KB.
> As the struct includes the state of all 32 private (per-VCPU) interrupts,
> we are at 3840 bytes on arm64 at the moment already. Growing the per-IRQ
> VGIC structure even slightly makes the VCPU quickly exceed the 4K limit.
> The new VGIC will need more space per virtual IRQ. I spent a few hours
> trying to trim this down, but couldn't get it below 4KB, even with the
> nasty hacks piling up to save some bytes here and there.
> It turns out that beyond efficiency, maybe, there is no real technical
> reason this struct has to fit in one page, so lifting the limit to two
> pages seems like the most pragmatic solution.
> Restrict this to compiling with the new VGIC and for ARM64 only.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> Changelog v2 ... v3:
> - rework alloc_vcpu_struct() to avoid nasty #ifdef
> 
> Changelog v1 ... v2:
> - confine change to new VGIC and ARM64 only
> 
>   xen/arch/arm/domain.c | 25 +++++++++++++++++++++----
>   1 file changed, 21 insertions(+), 4 deletions(-)
> 
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 9688e62f78..23bda3f7db 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -505,19 +505,36 @@ void dump_pageframe_info(struct domain *d)
>   
>   }
>   
> +/*
> + * The new VGIC has a bigger per-IRQ structure, so we need more than one
> + * page on ARM64. Cowardly increase the limit in this case.
> + */
> +#if defined(CONFIG_NEW_VGIC) && defined(CONFIG_ARM_64)
> +#define PAGES_PER_VCPU  2
> +#else
> +#define PAGES_PER_VCPU  1
> +#endif
> +
>   struct vcpu *alloc_vcpu_struct(void)
>   {
>       struct vcpu *v;
> -    BUILD_BUG_ON(sizeof(*v) > PAGE_SIZE);
> -    v = alloc_xenheap_pages(0, 0);
> +
> +    BUILD_BUG_ON(sizeof(*v) > PAGES_PER_VCPU * PAGE_SIZE);
> +    v = alloc_xenheap_pages(get_order_from_pages(PAGES_PER_VCPU), 0);

I was suggesting to use get_order_from_pages(sizeof (...)) so if we end 
up to be smaller, you don't lose a page for nothing. But I am ok with 
that too and can revisit later. So:

Acked-by: Julien Grall <julien.grall@arm.com>

>       if ( v != NULL )
> -        clear_page(v);
> +    {
> +        unsigned int i;
> +
> +        for ( i = 0; i < PAGES_PER_VCPU; i++ )
> +            clear_page((void *)v + i * PAGE_SIZE);
> +    }
> +
>       return v;
>   }
>   
>   void free_vcpu_struct(struct vcpu *v)
>   {
> -    free_xenheap_page(v);
> +    free_xenheap_pages(v, get_order_from_pages(PAGES_PER_VCPU));
>   }
>   
>   int vcpu_initialise(struct vcpu *v)
> 

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 39/39] ARM: VGIC: wire new VGIC(-v2) files into Xen build system
  2018-03-21 16:32 ` [PATCH v3 39/39] ARM: VGIC: wire new VGIC(-v2) files into Xen build system Andre Przywara
@ 2018-03-22  8:16   ` Julien Grall
  2018-03-22 10:39     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Julien Grall @ 2018-03-22  8:16 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini
  Cc: Wei Liu, George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich, xen-devel

Hi Andre,

On 03/21/2018 04:32 PM, Andre Przywara wrote:
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 131358a5a1..22c70ff7cd 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -981,6 +981,16 @@ unsigned int vgic_max_vcpus(const struct domain *d)
>       return min_t(unsigned int, MAX_VIRT_CPUS, vgic_vcpu_limit);
>   }
>   
> +#ifdef CONFIG_HAS_GICV3
> +void vgic_v3_setup_hw(paddr_t dbase,
> +                      unsigned int nr_rdist_regions,
> +                      const struct rdist_region *regions,
> +                      unsigned int intid_bits)
> +{
> +    /* Dummy implementation to allow building without actual vGICv3 support. */

One major inconvenience with that solution is GICv3 driver is going to 
be initialized but then you hit the BUG_ON() in domain_vgic_register. 
This is really not nice for the user but it is not obvious why the 
BUG_ON() is hit.

I am ok if you don't want to touch the Kconfig. But I would at least 
implement that helper with a panic("vGICv3 not yet supported with the 
new vGIC");

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 39/39] ARM: VGIC: wire new VGIC(-v2) files into Xen build system
  2018-03-22  8:16   ` Julien Grall
@ 2018-03-22 10:39     ` Andre Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-22 10:39 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini
  Cc: Wei Liu, George Dunlap, Andrew Cooper, Ian Jackson, Tim Deegan,
	Jan Beulich, xen-devel

Hi,

On 22/03/18 08:16, Julien Grall wrote:
> Hi Andre,
> 
> On 03/21/2018 04:32 PM, Andre Przywara wrote:
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index 131358a5a1..22c70ff7cd 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -981,6 +981,16 @@ unsigned int vgic_max_vcpus(const struct domain *d)
>>       return min_t(unsigned int, MAX_VIRT_CPUS, vgic_vcpu_limit);
>>   }
>>   +#ifdef CONFIG_HAS_GICV3
>> +void vgic_v3_setup_hw(paddr_t dbase,
>> +                      unsigned int nr_rdist_regions,
>> +                      const struct rdist_region *regions,
>> +                      unsigned int intid_bits)
>> +{
>> +    /* Dummy implementation to allow building without actual vGICv3
>> support. */
> 
> One major inconvenience with that solution is GICv3 driver is going to
> be initialized but then you hit the BUG_ON() in domain_vgic_register.
> This is really not nice for the user but it is not obvious why the
> BUG_ON() is hit.
> 
> I am ok if you don't want to touch the Kconfig. But I would at least
> implement that helper with a panic("vGICv3 not yet supported with the
> new vGIC");

Yes, that's a good point (and easy to implement!) ;-)

Also I think we should have something saying that we are using the new
VGIC, so we have it in the logs. Just realised this when I was wondering
if my machine is currently using the new or the old VGIC ;-)

I put something in the vgic_v2_setup_hw() implementation.

Cheers,
Andre.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend
  2018-03-22  3:48   ` Julien Grall
@ 2018-03-22 11:04     ` Andre Przywara
  2018-03-22 13:55       ` Julien Grall
  0 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-22 11:04 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel

This is a "patch to the patch" mentioned above, to make it clear what
changed:
We now take the desc lock in vgic_v2_fold_lr_state() when we are dealing
with a hardware IRQ. This is a bit complicated, because we have to obey
the existing locking order, so do our infamous "drop-take-retake" dance.
Also I print a message about using the new VGIC and fix that last
remaining "u32" usage.

Please note that I had to initialise "desc" to NULL because my compiler
(GCC 5.3) is not smart enough to see that we only use it with irq->hw
set and it's safe. Please let me know if it's me not being smart enough
here instead ;-)

Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
Hi,

will send a proper, merged v3a version of the patch separately.

Cheers,
Andre

 xen/arch/arm/vgic/vgic-v2.c | 43 ++++++++++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c
index 5516a8534f..3424a4a66f 100644
--- a/xen/arch/arm/vgic/vgic-v2.c
+++ b/xen/arch/arm/vgic/vgic-v2.c
@@ -43,6 +43,8 @@ void vgic_v2_setup_hw(paddr_t dbase, paddr_t cbase, paddr_t csize,
     gic_v2_hw_data.csize = csize;
     gic_v2_hw_data.vbase = vbase;
     gic_v2_hw_data.aliased_offset = aliased_offset;
+
+    printk("Using the new VGIC implementation.\n");
 }
 
 /*
@@ -69,6 +71,8 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu)
         struct gic_lr lr_val;
         uint32_t intid;
         struct vgic_irq *irq;
+        struct irq_desc *desc = NULL;
+        bool have_desc_lock = false;
 
         gic_hw_ops->read_lr(lr, &lr_val);
 
@@ -88,18 +92,30 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu)
         intid = lr_val.virq;
         irq = vgic_get_irq(vcpu->domain, vcpu, intid);
 
-        spin_lock_irqsave(&irq->irq_lock, flags);
+        local_irq_save(flags);
+        spin_lock(&irq->irq_lock);
+
+        /* The locking order forces us to drop and re-take the locks here. */
+        if ( irq->hw )
+        {
+            spin_unlock(&irq->irq_lock);
+
+            desc = irq_to_desc(irq->hwintid);
+            spin_lock(&desc->lock);
+            spin_lock(&irq->irq_lock);
+
+            /* This h/w IRQ should still be assigned to the virtual IRQ. */
+            ASSERT(irq->hw && desc->irq == irq->hwintid);
+
+            have_desc_lock = true;
+        }
 
         /*
          * If a hardware mapped IRQ has been handled for good, we need to
          * clear the _IRQ_INPROGRESS bit to allow handling of new IRQs.
          */
         if ( irq->hw && !lr_val.active && !lr_val.pending )
-        {
-            struct irq_desc *irqd = irq_to_desc(irq->hwintid);
-
-            clear_bit(_IRQ_INPROGRESS, &irqd->status);
-        }
+            clear_bit(_IRQ_INPROGRESS, &desc->status);
 
         /* Always preserve the active bit */
         irq->active = lr_val.active;
@@ -132,18 +148,19 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu)
          */
         if ( vgic_irq_is_mapped_level(irq) && lr_val.pending )
         {
-            struct irq_desc *irqd;
-
             ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
 
-            irqd = irq_to_desc(irq->hwintid);
-            irq->line_level = gic_read_pending_state(irqd);
+            irq->line_level = gic_read_pending_state(desc);
 
             if ( !irq->line_level )
-                gic_set_active_state(irqd, false);
+                gic_set_active_state(desc, false);
         }
 
-        spin_unlock_irqrestore(&irq->irq_lock, flags);
+        spin_unlock(&irq->irq_lock);
+        if ( have_desc_lock )
+            spin_unlock(&desc->lock);
+        local_irq_restore(flags);
+
         vgic_put_irq(vcpu->domain, irq);
     }
 
@@ -184,7 +201,7 @@ void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr)
 
         if ( vgic_irq_is_sgi(irq->intid) )
         {
-            u32 src = ffs(irq->source);
+            uint32_t src = ffs(irq->source);
 
             BUG_ON(!src);
             lr_val.virt.source = (src - 1);
-- 
2.14.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 03/39] ARM: GIC: Allow tweaking the active and pending state of an IRQ
  2018-03-22  1:51   ` Julien Grall
@ 2018-03-22 11:11     ` Andre Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-22 11:11 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel

Hi,

On 22/03/18 01:51, Julien Grall wrote:
> Hi Andre,
> 
> On 03/21/2018 04:31 PM, Andre Przywara wrote:
>> When playing around with hardware mapped, level triggered virtual IRQs,
>> there is the need to explicitly set the active or pending state of an
>> interrupt at some point.
>> To prepare the GIC for that, we introduce a set_active_state() and a
>> set_pending_state() function to let the VGIC manipulate the state of
>> an associated hardware IRQ.
>> This takes care of properly setting the _IRQ_INPROGRESS bit.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>> Changelog v2 ... v3:
>> - rework setting _IRQ_INPROGRESS bit:
>>    - no change when changing active state
>>    - unconditional set/clear on changing pending state
>> - drop introduction of gicv[23]_peek_irq() (only needed in the next
>> patch now)
>>
>> Changelog v1 ... v2:
>> - properly set _IRQ_INPROGRESS bit
>> - add gicv[23]_peek_irq() (pulled in from later patch)
>> - move wrappers functions into gic.h
>>
>>   xen/arch/arm/gic-v2.c     | 36 ++++++++++++++++++++++++++++++++++++
>>   xen/arch/arm/gic-v3.c     | 32 ++++++++++++++++++++++++++++++++
>>   xen/include/asm-arm/gic.h | 24 ++++++++++++++++++++++++
>>   3 files changed, 92 insertions(+)
>>
>> diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
>> index aa0fc6c1a1..d1f1578c05 100644
>> --- a/xen/arch/arm/gic-v2.c
>> +++ b/xen/arch/arm/gic-v2.c
>> @@ -243,6 +243,40 @@ static void gicv2_poke_irq(struct irq_desc *irqd,
>> uint32_t offset)
>>       writel_gicd(1U << (irqd->irq % 32), offset + (irqd->irq / 32) * 4);
>>   }
>>   +static void gicv2_set_active_state(struct irq_desc *irqd, bool active)
>> +{
>> +    ASSERT(spin_is_locked(&irqd->lock));
>> +
>> +    if ( active )
>> +    {
>> +        if ( test_bit(_IRQ_GUEST, &irqd->status) )
> 
> I don't understand why you only set/clear INPROGRESS bit for interrupt
> routed to guest. This will matter when releasing interrupt used by Xen
> (see release_irq).

D'oh, indeed! Seems like I am too focused on the _V_GIC these days ;-)

Fixed.

Cheers,
Andre.

> Note that I don't expect this helper to be call on Xen IRQ, but I think
> we should make
> 
> Other than same remark on GICv3 code, the pending implementation looks
> good to me now.
> 
> Cheers,
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq
  2018-03-22  3:52   ` Julien Grall
@ 2018-03-22 11:15     ` Andre Przywara
  2018-03-26 23:34       ` Stefano Stabellini
  0 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-22 11:15 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel

Hi,

On 22/03/18 03:52, Julien Grall wrote:
> Hi Andre,
> 
> On 03/21/2018 04:32 PM, Andre Przywara wrote:
>> Tell Xen whether a particular VCPU has an IRQ that needs handling
>> in the guest. This is used to decide whether a VCPU is runnable or
>> if a hypercall should be preempted to let the guest handle the IRQ.
>>
>> This is based on Linux commit 90eee56c5f90, written by Eric Auger.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>> Changelog v2 ... v3:
>> - adjust vgic_vcpu_pending_irq() to return integers, not false/true
> 
> I would have preferred to have the return switch to bool instead. I
> guess this can be done on a follow-up. With one comment below:

I did that originally, but then you meanwhile merged that first patch
already. So I didn't want to add another patch to this series.
I am fine with changing this afterwards, probably as part of a fixup series.

> Reviewed-by: Julien Grall <julien.grall@arm.com>

Thanks!

Cheers,
Andre.

>>
>> Changelog v1 ... v2:
>> - adjust to new vgic_vcpu_pending_irq() prototype, drop wrapper
>>
>>   xen/arch/arm/vgic/vgic.c | 37 +++++++++++++++++++++++++++++++++++++
>>   1 file changed, 37 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index 2fa595f4f7..925cda4580 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -647,6 +647,43 @@ void vgic_sync_to_lrs(void)
>>       gic_hw_ops->update_hcr_status(GICH_HCR_EN, 1);
>>   }
>>   +/**
>> + * vgic_vcpu_pending_irq() - determine if interrupts need to be injected
>> + * @vcpu: The vCPU on which to check for interrupts.
>> + *
>> + * Checks whether there is an interrupt on the given VCPU which needs
>> + * handling in the guest. This requires at least one IRQ to be pending
>> + * and enabled.
>> + *
>> + * Returns: 1 if the guest should run to handle interrupts, 0 otherwise.
> 
> NIT: Because of "ret = irq_is_pending(irq) && irq->enabled", you will
> return a non-zero value if the guest should run to handle interrupts.
> 
>> + */
>> +int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>> +{
>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
>> +    struct vgic_irq *irq;
>> +    unsigned long flags;
>> +    int ret = 0;
>> +
>> +    if ( !vcpu->domain->arch.vgic.enabled )
>> +        return 0;
>> +
>> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
>> +
>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>> +    {
>> +        spin_lock(&irq->irq_lock);
>> +        ret = irq_is_pending(irq) && irq->enabled;
>> +        spin_unlock(&irq->irq_lock);
>> +
>> +        if ( ret )
>> +            break;
>> +    }
>> +
>> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
>> +
>> +    return ret;
>> +}
>> +
>>   /*
>>    * Local variables:
>>    * mode: C
>>
> 
> Cheers,
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC
  2018-03-22  8:00   ` Julien Grall
@ 2018-03-22 11:18     ` Andre Przywara
  2018-03-27 22:50     ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-22 11:18 UTC (permalink / raw)
  To: Julien Grall, Stefano Stabellini; +Cc: xen-devel

Hi,

On 22/03/18 08:00, Julien Grall wrote:
> Hi Andre,
> 
> On 03/21/2018 04:32 PM, Andre Przywara wrote:
>> This patch implements the function which is called by Xen when it wants
>> to register the virtual GIC.
>> This also implements vgic_max_vcpus() for the new VGIC, which reports
>> back the maximum number of VCPUs a certain GIC model supports. Similar
>> to the counterpart in the "old" VGIC, we return some maximum value if
>> the VGIC has not been initialised yet.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> 
> Thank you for the update. We will have to remove the GIC_INVALID case
> once Andrew's series is merged. If his series is merged before yours, it
> would not be an issue as that case should never be hit.

Yes, for my first reply I didn't originally see that his patch was a 20/20.

So I changed my mind and decided to not rely on this series ;-)
We can indeed fix this up later.

> Reviewed-by: Julien Grall <julien.grall@arm.com>

Thanks!

Andre.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend
  2018-03-22 11:04     ` Andre Przywara
@ 2018-03-22 13:55       ` Julien Grall
  0 siblings, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-22 13:55 UTC (permalink / raw)
  To: Andre Przywara, Stefano Stabellini; +Cc: xen-devel

Hi Andre,

On 03/22/2018 11:04 AM, Andre Przywara wrote:
> This is a "patch to the patch" mentioned above, to make it clear what
> changed:
> We now take the desc lock in vgic_v2_fold_lr_state() when we are dealing
> with a hardware IRQ. This is a bit complicated, because we have to obey
> the existing locking order, so do our infamous "drop-take-retake" dance.
> Also I print a message about using the new VGIC and fix that last
> remaining "u32" usage.
> 
> Please note that I had to initialise "desc" to NULL because my compiler
> (GCC 5.3) is not smart enough to see that we only use it with irq->hw
> set and it's safe. Please let me know if it's me not being smart enough
> here instead ;-)

I would not be surprised that even recent compiler can't deal with that. 
It would require quite some work from the compiler to know that desc is 
only used when irq->hw.

I will comment the code on 3a.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version
  2018-03-21 16:31 ` [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version Andre Przywara
  2018-03-22  1:39   ` Julien Grall
@ 2018-03-26 20:08   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 20:08 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The enum gic_version at the moment just contains GIC_V2 and GIC_V3,
> where GIC_V2 happens to map to 0. So without having initialised a
> variable of that type, we will read back GIC_V2 (when allocated with zeroing
> the memory).
> To prevent ambiguities and to give an explicitly uninitialised state, add
> a new first member: GIC_INVALID. Also make it obvious that this has a
> "0" encoding.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/include/asm-arm/gic.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 565b0875ca..3079387e06 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -227,6 +227,7 @@ struct gic_lr {
>  };
>  
>  enum gic_version {
> +    GIC_INVALID = 0,    /* the default until explicitly set up */
>      GIC_V2,
>      GIC_V3,
>  };
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 04/39] ARM: GIC: Allow reading pending state of a hardware IRQ
  2018-03-21 16:32 ` [PATCH v3 04/39] ARM: GIC: Allow reading pending state of a hardware IRQ Andre Przywara
@ 2018-03-26 20:08   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 20:08 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> To synchronize level triggered interrupts which are mapped into a guest,
> we need to update the virtual line level at certain points in time.
> For a hardware mapped interrupt the GIC is the only place where we can
> easily access this information.
> Implement a gic_hw_operations member to return the pending state of a
> particular interrupt. Due to hardware limitations this only works for
> private interrupts of the current CPU, so there is no CPU field in the
> prototype.
> This adds gicv2/3_peek_irq() helper functions, to read a bit in a bitmap
> spread over several MMIO registers.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
> Changelog v2 ... v3:
> - introduce gicv[23]_peek_irq() (moved from patch before)
> 
>  xen/arch/arm/gic-v2.c     | 15 +++++++++++++++
>  xen/arch/arm/gic-v3.c     | 19 +++++++++++++++++++
>  xen/include/asm-arm/gic.h | 11 +++++++++++
>  3 files changed, 45 insertions(+)
> 
> diff --git a/xen/arch/arm/gic-v2.c b/xen/arch/arm/gic-v2.c
> index d1f1578c05..b440a45e8e 100644
> --- a/xen/arch/arm/gic-v2.c
> +++ b/xen/arch/arm/gic-v2.c
> @@ -243,6 +243,15 @@ static void gicv2_poke_irq(struct irq_desc *irqd, uint32_t offset)
>      writel_gicd(1U << (irqd->irq % 32), offset + (irqd->irq / 32) * 4);
>  }
>  
> +static bool gicv2_peek_irq(struct irq_desc *irqd, uint32_t offset)
> +{
> +    uint32_t reg;
> +
> +    reg = readl_gicd(offset + (irqd->irq / 32) * 4) & (1U << (irqd->irq % 32));
> +
> +    return reg;
> +}
> +
>  static void gicv2_set_active_state(struct irq_desc *irqd, bool active)
>  {
>      ASSERT(spin_is_locked(&irqd->lock));
> @@ -580,6 +589,11 @@ static unsigned int gicv2_read_apr(int apr_reg)
>     return readl_gich(GICH_APR);
>  }
>  
> +static bool gicv2_read_pending_state(struct irq_desc *irqd)
> +{
> +    return gicv2_peek_irq(irqd, GICD_ISPENDR);
> +}
> +
>  static void gicv2_irq_enable(struct irq_desc *desc)
>  {
>      unsigned long flags;
> @@ -1325,6 +1339,7 @@ const static struct gic_hw_operations gicv2_ops = {
>      .write_lr            = gicv2_write_lr,
>      .read_vmcr_priority  = gicv2_read_vmcr_priority,
>      .read_apr            = gicv2_read_apr,
> +    .read_pending_state  = gicv2_read_pending_state,
>      .make_hwdom_dt_node  = gicv2_make_hwdom_dt_node,
>      .make_hwdom_madt     = gicv2_make_hwdom_madt,
>      .get_hwdom_extra_madt_size = gicv2_get_hwdom_extra_madt_size,
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index f244d51661..5c9a783968 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -444,6 +444,19 @@ static void gicv3_poke_irq(struct irq_desc *irqd, u32 offset, bool wait_for_rwp)
>          gicv3_wait_for_rwp(irqd->irq);
>  }
>  
> +static bool gicv3_peek_irq(struct irq_desc *irqd, u32 offset)
> +{
> +    void __iomem *base;
> +    unsigned int irq = irqd->irq;
> +
> +    if ( irq >= NR_GIC_LOCAL_IRQS)
> +        base = GICD + (irq / 32) * 4;
> +    else
> +        base = GICD_RDIST_SGI_BASE;
> +
> +    return !!(readl(base + offset) & (1U << (irq % 32)));
> +}
> +
>  static void gicv3_unmask_irq(struct irq_desc *irqd)
>  {
>      gicv3_poke_irq(irqd, GICD_ISENABLER, false);
> @@ -1144,6 +1157,11 @@ static unsigned int gicv3_read_apr(int apr_reg)
>      }
>  }
>  
> +static bool gicv3_read_pending_state(struct irq_desc *irqd)
> +{
> +    return gicv3_peek_irq(irqd, GICD_ISPENDR);
> +}
> +
>  static void gicv3_irq_enable(struct irq_desc *desc)
>  {
>      unsigned long flags;
> @@ -1812,6 +1830,7 @@ static const struct gic_hw_operations gicv3_ops = {
>      .write_lr            = gicv3_write_lr,
>      .read_vmcr_priority  = gicv3_read_vmcr_priority,
>      .read_apr            = gicv3_read_apr,
> +    .read_pending_state  = gicv3_read_pending_state,
>      .secondary_init      = gicv3_secondary_cpu_init,
>      .make_hwdom_dt_node  = gicv3_make_hwdom_dt_node,
>      .make_hwdom_madt     = gicv3_make_hwdom_madt,
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 2aca243ac3..58b910fe6a 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -373,6 +373,8 @@ struct gic_hw_operations {
>      unsigned int (*read_vmcr_priority)(void);
>      /* Read APRn register */
>      unsigned int (*read_apr)(int apr_reg);
> +    /* Query the pending state of an interrupt at the distributor level. */
> +    bool (*read_pending_state)(struct irq_desc *irqd);
>      /* Secondary CPU init */
>      int (*secondary_init)(void);
>      /* Create GIC node for the hardware domain */
> @@ -417,6 +419,15 @@ static inline void gic_set_pending_state(struct irq_desc *irqd, bool state)
>      gic_hw_ops->set_pending_state(irqd, state);
>  }
>  
> +/*
> + * Read the pending state of an interrupt from the distributor.
> + * For private IRQs this only works for those of the current CPU.
> + */
> +static inline bool gic_read_pending_state(struct irq_desc *irqd)
> +{
> +    return gic_hw_ops->read_pending_state(irqd);
> +}
> +
>  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,
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-21 16:32 ` [PATCH v3 06/39] ARM: evtchn: " Andre Przywara
  2018-03-22  2:08   ` Julien Grall
@ 2018-03-26 20:08   ` Stefano Stabellini
  2018-03-28  0:01   ` Stefano Stabellini
  2 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 20:08 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The event channel IRQ has level triggered semantics, however the current
> VGIC treats everything as edge triggered.
> To correctly process those IRQs, we have to lower the (virtual) IRQ line
> at some point in time, depending on whether ther interrupt condition
> still prevails.
> Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
> line match its status, and call this function upon every hypervisor
> entry.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/domain.c       | 7 +++++++
>  xen/arch/arm/traps.c        | 1 +
>  xen/include/asm-arm/event.h | 1 +
>  3 files changed, 9 insertions(+)
> 
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index ff97f2bc76..9688e62f78 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
>      vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
>  }
>  
> +void vcpu_update_evtchn_irq(struct vcpu *v)
> +{
> +    bool pending = vcpu_info(v, evtchn_upcall_pending);
> +
> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
> +}
> +
>  /* The ARM spec declares that even if local irqs are masked in
>   * the CPSR register, an irq should wake up a cpu from WFI anyway.
>   * For this reason we need to check for irqs that need delivery,
> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> index 2638446693..5c18e918b0 100644
> --- a/xen/arch/arm/traps.c
> +++ b/xen/arch/arm/traps.c
> @@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
>           * trap and how it can be optimised.
>           */
>          vtimer_update_irqs(current);
> +        vcpu_update_evtchn_irq(current);
>  #endif
>  
>          vgic_sync_from_lrs(current);
> diff --git a/xen/include/asm-arm/event.h b/xen/include/asm-arm/event.h
> index c7a415ef57..2f51864043 100644
> --- a/xen/include/asm-arm/event.h
> +++ b/xen/include/asm-arm/event.h
> @@ -6,6 +6,7 @@
>  
>  void vcpu_kick(struct vcpu *v);
>  void vcpu_mark_events_pending(struct vcpu *v);
> +void vcpu_update_evtchn_irq(struct vcpu *v);
>  void vcpu_block_unless_event_pending(struct vcpu *v);
>  
>  static inline int vcpu_event_delivery_is_enabled(struct vcpu *v)
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 07/39] ARM: vPL011: Use the VGIC's level triggered IRQs handling if available
  2018-03-21 16:32 ` [PATCH v3 07/39] ARM: vPL011: Use the VGIC's level triggered IRQs handling if available Andre Przywara
@ 2018-03-26 20:20   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 20:20 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The emulated ARM SBSA UART is using level triggered IRQ semantics,
> however the current VGIC can only handle edge triggered IRQs, really.
> Disable the existing workaround for this problem in case we have the
> new VGIC in place, which can properly handle level triggered IRQs.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>

> ---
>  xen/arch/arm/vpl011.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
> index 5dcf4bec18..a281eabd7e 100644
> --- a/xen/arch/arm/vpl011.c
> +++ b/xen/arch/arm/vpl011.c
> @@ -54,6 +54,7 @@ static void vpl011_update_interrupt_status(struct domain *d)
>       */
>      ASSERT(spin_is_locked(&vpl011->lock));
>  
> +#ifndef CONFIG_NEW_VGIC
>      /*
>       * TODO: PL011 interrupts are level triggered which means
>       * that interrupt needs to be set/clear instead of being
> @@ -71,6 +72,9 @@ static void vpl011_update_interrupt_status(struct domain *d)
>          vgic_inject_irq(d, NULL, GUEST_VPL011_SPI, true);
>  
>      vpl011->shadow_uartmis = uartmis;
> +#else
> +    vgic_inject_irq(d, NULL, GUEST_VPL011_SPI, uartmis);
> +#endif
>  }
>  
>  static uint8_t vpl011_read_data(struct domain *d)
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly
  2018-03-21 16:32 ` [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly Andre Przywara
  2018-03-22  1:58   ` Julien Grall
@ 2018-03-26 20:28   ` Stefano Stabellini
  2018-03-27 13:06     ` Andre Przywara
  1 sibling, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 20:28 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The ARM Generic Timer uses a level-sensitive interrupt semantic. We
> easily catch when the line goes high, as this triggers the hardware IRQ.
> However we also have to keep track of when the line lowers, as the
> emulation depends on it: Upon entering the guest, the new VGIC will
> *clear* the virtual interrupt line, so it needs to re-sample the actual
> state after returning from the guest.
> So we have to sync the state of the interrupt condition at certain
> points to catch when the line goes low and we can remove the vtimer vIRQ
> from the vGIC (and the LR).
> The VGIC in Xen so far only implemented edge triggered vIRQs, really, so
> we need to add new functionality to re-sample the interrupt state.
> Do this only when the new VGIC is in use.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> Changelog v2 ... v3:
> - move vtimer_sync() from time.c into vtimer.c
> - rename function to vtimer_update_irqs()
> - refactor functionality into new static function, to ...
> - handle physical timer as well
> - extending comments
> 
> Changelog v1 ... v2:
> - restrict to new VGIC
> - add TODO: comment
> 
>  xen/arch/arm/traps.c         | 11 ++++++++++
>  xen/arch/arm/vtimer.c        | 49 ++++++++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/vtimer.h |  1 +
>  3 files changed, 61 insertions(+)
> 
> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> index 7411bff7a7..2638446693 100644
> --- a/xen/arch/arm/traps.c
> +++ b/xen/arch/arm/traps.c
> @@ -2024,6 +2024,17 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
>          if ( current->arch.hcr_el2 & HCR_VA )
>              current->arch.hcr_el2 = READ_SYSREG(HCR_EL2);
>  
> +#ifdef CONFIG_NEW_VGIC
> +        /*
> +         * We need to update the state of our emulated devices using level
> +         * triggered interrupts before syncing back the VGIC state.
> +         *
> +         * TODO: Investigate whether this is necessary to do on every
> +         * trap and how it can be optimised.
> +         */
> +        vtimer_update_irqs(current);
> +#endif
> +
>          vgic_sync_from_lrs(current);
>      }
>  }
> diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c
> index 8164f6c7f1..c99dd237d1 100644
> --- a/xen/arch/arm/vtimer.c
> +++ b/xen/arch/arm/vtimer.c
> @@ -334,6 +334,55 @@ bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr)
>      }
>  }
>  
> +static void vtimer_update_irq(struct vcpu *v, struct vtimer *vtimer,
> +                              uint32_t vtimer_ctl)
> +{
> +    bool level;
> +
> +    /* Filter for the three bits that determine the status of the timer */
> +    vtimer_ctl &= (CNTx_CTL_ENABLE | CNTx_CTL_PENDING | CNTx_CTL_MASK);
> +
> +    /* The level is high if the timer is pending and enabled, but not masked. */
> +    level = (vtimer_ctl == (CNTx_CTL_ENABLE | CNTx_CTL_PENDING));
> +
> +    /*
> +     * This is mostly here to *lower* the virtual interrupt line if the timer
> +     * is no longer pending.
> +     * We would have injected an IRQ already via SOFTIRQ when the timer expired.
> +     * Doing it here again is basically a NOP if the line was already high.
> +     */
> +    vgic_inject_irq(v->domain, v, vtimer->irq, level);
> +}
> +
> +/**
> + * vtimer_update_irqs() - update the virtual timers' IRQ lines after a guest run
> + * @vcpu: The VCPU to sync the timer state
> + *
> + * After returning from a guest, update the state of the timers' virtual
> + * interrupt lines, to model the level triggered interrupts correctly.
> + * If the guest has handled a timer interrupt, the virtual interrupt line
> + * needs to be lowered explicitly. vgic_inject_irq() takes care of that.
> + */
> +void vtimer_update_irqs(struct vcpu *v)
> +{
> +    /*
> +     * For the virtual timer we read the current state from the hardware.
> +     * Technically we should keep the CNTx_CTL_MASK bit here, to catch if
> +     * the timer interrupt is masked. However Xen *always* masks the timer
> +     * upon entering the hypervisor, leaving it up to the guest to un-mask it.
> +     * So we would always read a "low" level, despite the condition being
> +     * actually "high".  Ignoring the mask bit solves this (for now).
> +     *
> +     * TODO: The proper fix for this is to make vtimer vIRQ hardware mapped,
> +     * but this requires reworking the arch timer to implement this.
> +     */
> +    vtimer_update_irq(v, &v->arch.virt_timer,
> +                      READ_SYSREG32(CNTV_CTL_EL0) & ~CNTx_CTL_MASK);

Yes, but won't this have the opposite effect? Meaning that it will
always read as "high" for the virtual timer (because we remove the MASK
and that is the only thing that can cause a "low" read in
vtimer_update_irq if it's enabled and pending)?

It seems to me that it would be better to remove the update of the
virtual timer -- this seems to have the potential of causing problems.


> +    /* For the physical timer we rely on our emulated state. */
> +    vtimer_update_irq(v, &v->arch.phys_timer, v->arch.phys_timer.ctl);
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/include/asm-arm/vtimer.h b/xen/include/asm-arm/vtimer.h
> index 5aaddc6f63..91d88b377f 100644
> --- a/xen/include/asm-arm/vtimer.h
> +++ b/xen/include/asm-arm/vtimer.h
> @@ -27,6 +27,7 @@ extern bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr);
>  extern int virt_timer_save(struct vcpu *v);
>  extern int virt_timer_restore(struct vcpu *v);
>  extern void vcpu_timer_destroy(struct vcpu *v);
> +void vtimer_update_irqs(struct vcpu *v);
>  
>  #endif
>  
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 08/39] ARM: new VGIC: Add data structure definitions
  2018-03-21 16:32 ` [PATCH v3 08/39] ARM: new VGIC: Add data structure definitions Andre Przywara
@ 2018-03-26 20:41   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 20:41 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Add a new header file for the new and improved GIC implementation.
> The big change is that we now have a struct vgic_irq per IRQ instead
> of spreading all the information over various bitmaps in the ranks.
> 
> We include this new header conditionally from within the old header
> file for the time being to avoid touching all the users.
> 
> This is based on Linux commit b18b57787f5e, written by Christoffer Dall.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>

> ---
>  xen/include/asm-arm/new_vgic.h | 198 +++++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-arm/vgic.h     |   6 ++
>  2 files changed, 204 insertions(+)
>  create mode 100644 xen/include/asm-arm/new_vgic.h
> 
> diff --git a/xen/include/asm-arm/new_vgic.h b/xen/include/asm-arm/new_vgic.h
> new file mode 100644
> index 0000000000..97d622bff6
> --- /dev/null
> +++ b/xen/include/asm-arm/new_vgic.h
> @@ -0,0 +1,198 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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_NEW_VGIC_H
> +#define __ASM_ARM_NEW_VGIC_H
> +
> +#include <asm/atomic.h>
> +#include <asm/mmio.h>
> +#include <xen/list.h>
> +#include <xen/mm.h>
> +#include <xen/spinlock.h>
> +
> +#define VGIC_V3_MAX_CPUS        255
> +#define VGIC_V2_MAX_CPUS        8
> +#define VGIC_NR_SGIS            16
> +#define VGIC_NR_PPIS            16
> +#define VGIC_NR_PRIVATE_IRQS    (VGIC_NR_SGIS + VGIC_NR_PPIS)
> +#define VGIC_MAX_PRIVATE        (VGIC_NR_PRIVATE_IRQS - 1)
> +#define VGIC_MAX_SPI            1019
> +#define VGIC_MAX_RESERVED       1023
> +#define VGIC_MIN_LPI            8192
> +
> +#define irq_is_ppi(irq) ((irq) >= VGIC_NR_SGIS && (irq) < VGIC_NR_PRIVATE_IRQS)
> +#define irq_is_spi(irq) ((irq) >= VGIC_NR_PRIVATE_IRQS && \
> +                         (irq) <= VGIC_MAX_SPI)
> +
> +enum vgic_type {
> +    VGIC_V2,        /* Good ol' GICv2 */
> +    VGIC_V3,        /* New fancy GICv3 */
> +};
> +
> +#define VGIC_V2_MAX_LRS         (1 << 6)
> +#define VGIC_V3_MAX_LRS         16
> +#define VGIC_V3_LR_INDEX(lr)    (VGIC_V3_MAX_LRS - 1 - lr)
> +
> +#define VGIC_CONFIG_EDGE        false
> +#define VGIC_CONFIG_LEVEL       true
> +
> +struct vgic_irq {
> +    struct list_head ap_list;
> +
> +    struct vcpu *vcpu;          /*
> +                                 * SGIs and PPIs: The VCPU
> +                                 * SPIs and LPIs: The VCPU whose ap_list
> +                                 * this is queued on.
> +                                 */
> +
> +    struct vcpu *target_vcpu;   /*
> +                                 * The VCPU that this interrupt should
> +                                 * be sent to, as a result of the
> +                                 * targets reg (v2) or the affinity reg (v3).
> +                                 */
> +
> +    spinlock_t irq_lock;        /* Protects the content of the struct */
> +    uint32_t intid;             /* Guest visible INTID */
> +    atomic_t refcount;          /* Used for LPIs */
> +    uint32_t hwintid;           /* HW INTID number */
> +    union
> +    {
> +        struct {
> +            uint8_t targets;    /* GICv2 target VCPUs mask */
> +            uint8_t source;     /* GICv2 SGIs only */
> +        };
> +        uint32_t mpidr;         /* GICv3 target VCPU */
> +    };
> +    uint8_t priority;
> +    bool line_level:1;          /* Level only */
> +    bool pending_latch:1;       /*
> +                                 * The pending latch state used to
> +                                 * calculate the pending state for both
> +                                 * level and edge triggered IRQs.
> +                                 */
> +    bool active:1;              /* not used for LPIs */
> +    bool enabled:1;
> +    bool hw:1;                  /* Tied to HW IRQ */
> +    bool config:1;              /* Level or edge */
> +    struct list_head lpi_list;  /* Used to link all LPIs together */
> +};
> +
> +enum iodev_type {
> +    IODEV_DIST,
> +    IODEV_REDIST,
> +};
> +
> +struct vgic_io_device {
> +    gfn_t base_fn;
> +    struct vcpu *redist_vcpu;
> +    const struct vgic_register_region *regions;
> +    enum iodev_type iodev_type;
> +    unsigned int nr_regions;
> +};
> +
> +struct vgic_dist {
> +    bool                ready;
> +    bool                initialized;
> +
> +    /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
> +    uint32_t            version;
> +
> +    /* Do injected MSIs require an additional device ID? */
> +    bool                msis_require_devid;
> +
> +    unsigned int        nr_spis;
> +
> +    /* base addresses in guest physical address space: */
> +    paddr_t             vgic_dist_base;     /* distributor */
> +    union
> +    {
> +        /* either a GICv2 CPU interface */
> +        paddr_t         vgic_cpu_base;
> +        /* or a number of GICv3 redistributor regions */
> +        struct
> +        {
> +            paddr_t     vgic_redist_base;
> +            paddr_t     vgic_redist_free_offset;
> +        };
> +    };
> +
> +    /* distributor enabled */
> +    bool                enabled;
> +
> +    struct vgic_irq     *spis;
> +    unsigned long       *allocated_irqs; /* bitmap of IRQs allocated */
> +
> +    struct vgic_io_device   dist_iodev;
> +
> +    bool                has_its;
> +
> +    /*
> +     * Contains the attributes and gpa of the LPI configuration table.
> +     * Since we report GICR_TYPER.CommonLPIAff as 0b00, we can share
> +     * one address across all redistributors.
> +     * GICv3 spec: 6.1.2 "LPI Configuration tables"
> +     */
> +    uint64_t            propbaser;
> +
> +    /* Protects the lpi_list and the count value below. */
> +    spinlock_t          lpi_list_lock;
> +    struct list_head    lpi_list_head;
> +    unsigned int        lpi_list_count;
> +};
> +
> +struct vgic_cpu {
> +    struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
> +
> +    struct list_head ap_list_head;
> +    spinlock_t ap_list_lock;    /* Protects the ap_list */
> +
> +    unsigned int used_lrs;
> +
> +    /*
> +     * List of IRQs that this VCPU should consider because they are either
> +     * Active or Pending (hence the name; AP list), or because they recently
> +     * were one of the two and need to be migrated off this list to another
> +     * VCPU.
> +     */
> +
> +    /*
> +     * Members below are used with GICv3 emulation only and represent
> +     * parts of the redistributor.
> +     */
> +    struct vgic_io_device   rd_iodev;
> +    struct vgic_io_device   sgi_iodev;
> +
> +    /* Contains the attributes and gpa of the LPI pending tables. */
> +    uint64_t pendbaser;
> +
> +    bool lpis_enabled;
> +
> +    /* Cache guest priority bits */
> +    uint32_t num_pri_bits;
> +
> +    /* Cache guest interrupt ID bits */
> +    uint32_t num_id_bits;
> +};
> +
> +#endif /* __ASM_ARM_NEW_VGIC_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/vgic.h b/xen/include/asm-arm/vgic.h
> index 0787ba9549..2a58ea30fe 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -18,6 +18,10 @@
>  #ifndef __ASM_ARM_VGIC_H__
>  #define __ASM_ARM_VGIC_H__
>  
> +#ifdef CONFIG_NEW_VGIC
> +#include <asm/new_vgic.h>
> +#else
> +
>  #include <xen/bitops.h>
>  #include <xen/radix-tree.h>
>  #include <xen/rbtree.h>
> @@ -299,6 +303,8 @@ extern bool vgic_to_sgi(struct vcpu *v, register_t sgir,
>                          const struct sgi_target *target);
>  extern bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq);
>  
> +#endif /* !CONFIG_NEW_VGIC */
> +
>  /*** Common VGIC functions used by Xen arch code ****/
>  
>  /*
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 09/39] ARM: new VGIC: Add accessor to new struct vgic_irq instance
  2018-03-22  2:11   ` Julien Grall
@ 2018-03-26 20:46     ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 20:46 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Andre Przywara

On Thu, 22 Mar 2018, Julien Grall wrote:
> Hi Andre,
> 
> On 03/21/2018 04:32 PM, Andre Przywara wrote:
> > The new VGIC implementation centers around a struct vgic_irq instance
> > per virtual IRQ.
> > Provide a function to retrieve the right instance for a given IRQ
> > number and (in case of private interrupts) the right VCPU.
> > This also includes the corresponding put function, which does nothing
> > for private interrupts and SPIs, but handles the ref-counting for LPIs.
> > 
> > This is based on Linux commit 64a959d66e47, written by Christoffer Dall.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> > ---
> > Changelog v2 ... v3:
> > - extend comments to note preliminary nature of vgic_get_lpi()
> 
> Thank you for the update.
> 
> > 
> > Changelog v1 ... v2:
> > - reorder header file inclusion
> > 
> >   xen/arch/arm/vgic/vgic.c | 134
> > +++++++++++++++++++++++++++++++++++++++++++++++
> >   xen/arch/arm/vgic/vgic.h |  41 +++++++++++++++
> >   2 files changed, 175 insertions(+)
> >   create mode 100644 xen/arch/arm/vgic/vgic.c
> >   create mode 100644 xen/arch/arm/vgic/vgic.h
> > 
> > diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> > new file mode 100644
> > index 0000000000..a818e382b1
> > --- /dev/null
> > +++ b/xen/arch/arm/vgic/vgic.c
> > @@ -0,0 +1,134 @@
> > +/*
> > + * Copyright (C) 2015, 2016 ARM Ltd.
> > + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
> > + *
> > + * 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/sched.h>
> > +#include <asm/bug.h>
> > +#include <asm/new_vgic.h>
> > +
> > +#include "vgic.h"
> > +
> > +/*
> > + * Iterate over the VM's list of mapped LPIs to find the one with a
> > + * matching interrupt ID and return a reference to the IRQ structure.
> > + *
> > + * TODO: This is more documentation of how it should be done. A list is
> > + * not a good data structure for Dom0's LPIs, it merely serves as an
> > + * example here how to properly do the locking, allocation and refcounting.
> > + * So lpi_list_head should be replaced with something more appropriate.
> > + */
> > +static struct vgic_irq *vgic_get_lpi(struct domain *d, u32 intid)
> 
> It looks like I forgot to mention it on previous version. Please replace u32
> with uint32_t.
> 
> [...]
> 
> > +struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
> > +                              u32 intid)
> 
> Here too.
> 
> > +{
> > +    /* SGIs and PPIs */
> > +    if ( intid <= VGIC_MAX_PRIVATE )
> > +        return &vcpu->arch.vgic.private_irqs[intid];
> > +
> > +    /* SPIs */
> > +    if ( intid <= VGIC_MAX_SPI )
> > +        return &d->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
> > +
> > +    /* LPIs */
> > +    if ( intid >= VGIC_MIN_LPI )
> > +        return vgic_get_lpi(d, intid);
> > +
> > +    ASSERT_UNREACHABLE();
> > +
> > +    return NULL;
> > +}
> > +
> 
> [...]
> 
> > diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> > new file mode 100644
> > index 0000000000..a3befd386b
> > --- /dev/null
> > +++ b/xen/arch/arm/vgic/vgic.h
> 
> [...]
> 
> > +struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
> > +                              u32 intid);
> 
> And here too.
> 
> With that:
> 
> Acked-by: Julien Grall <julien.grall@arm.com>

same here:
Acked-by: Stefano Stabellini <sstabellini@kernel.org>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 10/39] ARM: new VGIC: Implement virtual IRQ injection
  2018-03-21 16:32 ` [PATCH v3 10/39] ARM: new VGIC: Implement virtual IRQ injection Andre Przywara
@ 2018-03-26 21:01   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 21:01 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Provide a vgic_queue_irq_unlock() function which decides whether a
> given IRQ needs to be queued to a VCPU's ap_list.
> This should be called whenever an IRQ becomes pending or enabled,
> either as a result of a hardware IRQ injection, from devices emulated by
> Xen (like the architected timer) or from MMIO accesses to the distributor
> emulation.
> Also provides the necessary functions to allow to inject an IRQ to a guest.
> Since this is the first code that starts using our locking mechanism,
> we add some (hopefully) clear documentation of our locking strategy and
> requirements along with this patch.
> 
> This is based on Linux commit 81eeb95ddbab, written by Christoffer Dall.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/vgic/vgic.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic.h |  10 +++
>  2 files changed, 236 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index a818e382b1..f7dfd01c1d 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -17,10 +17,36 @@
>  
>  #include <xen/sched.h>
>  #include <asm/bug.h>
> +#include <asm/event.h>
>  #include <asm/new_vgic.h>
>  
>  #include "vgic.h"
>  
> +/*
> + * Locking order is always:
> + *   vgic->lock
> + *     vgic_cpu->ap_list_lock
> + *       vgic->lpi_list_lock
> + *         desc->lock
> + *           vgic_irq->irq_lock
> + *
> + * If you need to take multiple locks, always take the upper lock first,
> + * then the lower ones, e.g. first take the ap_list_lock, then the irq_lock.
> + * If you are already holding a lock and need to take a higher one, you
> + * have to drop the lower ranking lock first and re-acquire it after having
> + * taken the upper one.
> + *
> + * When taking more than one ap_list_lock at the same time, always take the
> + * lowest numbered VCPU's ap_list_lock first, so:
> + *   vcpuX->vcpu_id < vcpuY->vcpu_id:
> + *     spin_lock(vcpuX->arch.vgic.ap_list_lock);
> + *     spin_lock(vcpuY->arch.vgic.ap_list_lock);
> + *
> + * Since the VGIC must support injecting virtual interrupts from ISRs, we have
> + * to use the spin_lock_irqsave/spin_unlock_irqrestore versions of outer
> + * spinlocks for any lock that may be taken while injecting an interrupt.
> + */
> +
>  /*
>   * Iterate over the VM's list of mapped LPIs to find the one with a
>   * matching interrupt ID and return a reference to the IRQ structure.
> @@ -124,6 +150,206 @@ void vgic_put_irq(struct domain *d, struct vgic_irq *irq)
>      xfree(irq);
>  }
>  
> +/**
> + * vgic_target_oracle() - compute the target vcpu for an irq
> + * @irq:    The irq to route. Must be already locked.
> + *
> + * Based on the current state of the interrupt (enabled, pending,
> + * active, vcpu and target_vcpu), compute the next vcpu this should be
> + * given to. Return NULL if this shouldn't be injected at all.
> + *
> + * Requires the IRQ lock to be held.
> + *
> + * Returns: The pointer to the virtual CPU this interrupt should be injected
> + *          to. Will be NULL if this IRQ does not need to be injected.
> + */
> +static struct vcpu *vgic_target_oracle(struct vgic_irq *irq)
> +{
> +    ASSERT(spin_is_locked(&irq->irq_lock));
> +
> +    /* If the interrupt is active, it must stay on the current vcpu */
> +    if ( irq->active )
> +        return irq->vcpu ? : irq->target_vcpu;
> +
> +    /*
> +     * If the IRQ is not active but enabled and pending, we should direct
> +     * it to its configured target VCPU.
> +     * If the distributor is disabled, pending interrupts shouldn't be
> +     * forwarded.
> +     */
> +    if ( irq->enabled && irq_is_pending(irq) )
> +    {
> +        if ( unlikely(irq->target_vcpu &&
> +                      !irq->target_vcpu->domain->arch.vgic.enabled) )
> +            return NULL;
> +
> +        return irq->target_vcpu;
> +    }
> +
> +    /*
> +     * If neither active nor pending and enabled, then this IRQ should not
> +     * be queued to any VCPU.
> +     */
> +    return NULL;
> +}
> +
> +/*
> + * Only valid injection if changing level for level-triggered IRQs or for a
> + * rising edge.
> + */
> +static bool vgic_validate_injection(struct vgic_irq *irq, bool level)
> +{
> +    /* For edge interrupts we only care about a rising edge. */
> +    if ( irq->config == VGIC_CONFIG_EDGE )
> +        return level;
> +
> +    /* For level interrupts we have to act when the line level changes. */
> +    return irq->line_level != level;
> +}
> +
> +/**
> + * vgic_queue_irq_unlock() - Queue an IRQ to a VCPU, to be injected to a guest.
> + * @d:        The domain the virtual IRQ belongs to.
> + * @irq:      A pointer to the vgic_irq of the virtual IRQ, with the lock held.
> + * @flags:    The flags used when having grabbed the IRQ lock.
> + *
> + * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list.
> + * Do the queuing if necessary, taking the right locks in the right order.
> + *
> + * Needs to be entered with the IRQ lock already held, but will return
> + * with all locks dropped.
> + */
> +void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
> +                           unsigned long flags)
> +{
> +    struct vcpu *vcpu;
> +
> +    ASSERT(spin_is_locked(&irq->irq_lock));
> +
> +retry:
> +    vcpu = vgic_target_oracle(irq);
> +    if ( irq->vcpu || !vcpu )
> +    {
> +        /*
> +         * If this IRQ is already on a VCPU's ap_list, then it
> +         * cannot be moved or modified and there is no more work for
> +         * us to do.
> +         *
> +         * Otherwise, if the irq is not pending and enabled, it does
> +         * not need to be inserted into an ap_list and there is also
> +         * no more work for us to do.
> +         */
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +        /*
> +         * We have to kick the VCPU here, because we could be
> +         * queueing an edge-triggered interrupt for which we
> +         * get no EOI maintenance interrupt. In that case,
> +         * while the IRQ is already on the VCPU's AP list, the
> +         * VCPU could have EOI'ed the original interrupt and
> +         * won't see this one until it exits for some other
> +         * reason.
> +         */
> +        if ( vcpu )
> +            vcpu_kick(vcpu);
> +
> +        return;
> +    }
> +
> +    /*
> +     * We must unlock the irq lock to take the ap_list_lock where
> +     * we are going to insert this new pending interrupt.
> +     */
> +    spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +    /* someone can do stuff here, which we re-check below */
> +
> +    spin_lock_irqsave(&vcpu->arch.vgic.ap_list_lock, flags);
> +    spin_lock(&irq->irq_lock);
> +
> +    /*
> +     * Did something change behind our backs?
> +     *
> +     * There are two cases:
> +     * 1) The irq lost its pending state or was disabled behind our
> +     *    backs and/or it was queued to another VCPU's ap_list.
> +     * 2) Someone changed the affinity on this irq behind our
> +     *    backs and we are now holding the wrong ap_list_lock.
> +     *
> +     * In both cases, drop the locks and retry.
> +     */
> +
> +    if ( unlikely(irq->vcpu || vcpu != vgic_target_oracle(irq)) )
> +    {
> +        spin_unlock(&irq->irq_lock);
> +        spin_unlock_irqrestore(&vcpu->arch.vgic.ap_list_lock, flags);
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +        goto retry;
> +    }
> +
> +    /*
> +     * Grab a reference to the irq to reflect the fact that it is
> +     * now in the ap_list.
> +     */
> +    vgic_get_irq_kref(irq);
> +    list_add_tail(&irq->ap_list, &vcpu->arch.vgic.ap_list_head);
> +    irq->vcpu = vcpu;
> +
> +    spin_unlock(&irq->irq_lock);
> +    spin_unlock_irqrestore(&vcpu->arch.vgic.ap_list_lock, flags);
> +
> +    vcpu_kick(vcpu);
> +
> +    return;
> +}
> +
> +/**
> + * vgic_inject_irq() - Inject an IRQ from a device to the vgic
> + * @d:       The domain pointer
> + * @vcpu:    The vCPU for private IRQs (PPIs, SGIs). Ignored for SPIs and LPIs.
> + * @intid:   The INTID to inject a new state to.
> + * @level:   Edge-triggered:  true:  to trigger the interrupt
> + *                            false: to ignore the call
> + *           Level-sensitive  true:  raise the input signal
> + *                            false: lower the input signal
> + *
> + * Injects an instance of the given virtual IRQ into a domain.
> + * The VGIC is not concerned with devices being active-LOW or active-HIGH for
> + * level-sensitive interrupts.  You can think of the level parameter as 1
> + * being HIGH and 0 being LOW and all devices being active-HIGH.
> + */
> +void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,
> +                     bool level)
> +{
> +    struct vgic_irq *irq;
> +    unsigned long flags;
> +
> +    irq = vgic_get_irq(d, vcpu, intid);
> +    if ( !irq )
> +        return;
> +
> +    spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +    if ( !vgic_validate_injection(irq, level) )
> +    {
> +        /* Nothing to see here, move along... */
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +        vgic_put_irq(d, irq);
> +        return;
> +    }
> +
> +    if ( irq->config == VGIC_CONFIG_LEVEL )
> +        irq->line_level = level;
> +    else
> +        irq->pending_latch = true;
> +
> +    vgic_queue_irq_unlock(d, irq, flags);
> +    vgic_put_irq(d, irq);
> +
> +    return;
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index a3befd386b..f9e2eeb2d6 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -17,9 +17,19 @@
>  #ifndef __XEN_ARM_VGIC_VGIC_H__
>  #define __XEN_ARM_VGIC_VGIC_H__
>  
> +static inline bool irq_is_pending(struct vgic_irq *irq)
> +{
> +    if ( irq->config == VGIC_CONFIG_EDGE )
> +        return irq->pending_latch;
> +    else
> +        return irq->pending_latch || irq->line_level;
> +}
> +
>  struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
>                                u32 intid);
>  void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
> +void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
> +                           unsigned long flags);
>  
>  static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>  {
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 12/39] ARM: new VGIC: Add IRQ sorting
  2018-03-21 16:32 ` [PATCH v3 12/39] ARM: new VGIC: Add IRQ sorting Andre Przywara
@ 2018-03-26 21:16   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 21:16 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Adds the sorting function to cover the case where you have more IRQs
> to consider than you have LRs. We consider their priorities.
> This uses the new sort_list() implementation imported from Linux.
> 
> This is based on Linux commit 8e4447457965, written by Christoffer Dall.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>

> ---
>  xen/arch/arm/vgic/vgic.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 59 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index f7dfd01c1d..ee0de8d2e0 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -15,6 +15,7 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <xen/list_sort.h>
>  #include <xen/sched.h>
>  #include <asm/bug.h>
>  #include <asm/event.h>
> @@ -193,6 +194,64 @@ static struct vcpu *vgic_target_oracle(struct vgic_irq *irq)
>      return NULL;
>  }
>  
> +/*
> + * The order of items in the ap_lists defines how we'll pack things in LRs as
> + * well, the first items in the list being the first things populated in the
> + * LRs.
> + *
> + * A hard rule is that active interrupts can never be pushed out of the LRs
> + * (and therefore take priority) since we cannot reliably trap on deactivation
> + * of IRQs and therefore they have to be present in the LRs.
> + *
> + * Otherwise things should be sorted by the priority field and the GIC
> + * hardware support will take care of preemption of priority groups etc.
> + *
> + * Return negative if "a" sorts before "b", 0 to preserve order, and positive
> + * to sort "b" before "a".
> + */
> +static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
> +{
> +    struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list);
> +    struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list);
> +    bool penda, pendb;
> +    int ret;
> +
> +    spin_lock(&irqa->irq_lock);
> +    spin_lock(&irqb->irq_lock);
> +
> +    if ( irqa->active || irqb->active )
> +    {
> +        ret = (int)irqb->active - (int)irqa->active;
> +        goto out;
> +    }
> +
> +    penda = irqa->enabled && irq_is_pending(irqa);
> +    pendb = irqb->enabled && irq_is_pending(irqb);
> +
> +    if ( !penda || !pendb )
> +    {
> +        ret = (int)pendb - (int)penda;
> +        goto out;
> +    }
> +
> +    /* Both pending and enabled, sort by priority */
> +    ret = irqa->priority - irqb->priority;
> +out:
> +    spin_unlock(&irqb->irq_lock);
> +    spin_unlock(&irqa->irq_lock);
> +    return ret;
> +}
> +
> +/* Must be called with the ap_list_lock held */
> +static void vgic_sort_ap_list(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +
> +    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +    list_sort(NULL, &vgic_cpu->ap_list_head, vgic_irq_cmp);
> +}
> +
>  /*
>   * Only valid injection if changing level for level-triggered IRQs or for a
>   * rising edge.
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework
  2018-03-21 16:32 ` [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework Andre Przywara
  2018-03-22  2:16   ` Julien Grall
@ 2018-03-26 21:30   ` Stefano Stabellini
  2018-03-27 13:23     ` Andre Przywara
  1 sibling, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 21:30 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Implement the framework for syncing IRQs between our emulation and the
> list registers, which represent the guest's view of IRQs.
> This is done in vgic_sync_from_lrs() and vgic_sync_to_lrs(), which
> get called on guest entry and exit, respectively.
> The code talking to the actual GICv2/v3 hardware is added in the
> following patches.
> 
> This is based on Linux commit 0919e84c0fc1, written by Marc Zyngier.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Just one question below, but the code looks nice


> ---
> Changelog v2 ... v3:
> - replace "true" instead of "1" for the boolean parameter
> 
> Changelog v1 ... v2:
> - make functions void
> - do underflow setting directly (no v2/v3 indirection)
> - fix multiple SGIs injections (as the late Linux bugfix)
> 
>  xen/arch/arm/vgic/vgic.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic.h |   2 +
>  2 files changed, 234 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index ee0de8d2e0..52e1669888 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -409,6 +409,238 @@ void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,
>      return;
>  }
>  
> +/**
> + * vgic_prune_ap_list() - Remove non-relevant interrupts from the ap_list
> + *
> + * @vcpu:       The VCPU of which the ap_list should be pruned.
> + *
> + * Go over the list of interrupts on a VCPU's ap_list, and prune those that
> + * we won't have to consider in the near future.
> + * This removes interrupts that have been successfully handled by the guest,
> + * or that have otherwise became obsolete (not pending anymore).
> + * Also this moves interrupts between VCPUs, if their affinity has changed.
> + */
> +static void vgic_prune_ap_list(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +    struct vgic_irq *irq, *tmp;
> +    unsigned long flags;
> +
> +retry:
> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
> +
> +    list_for_each_entry_safe( irq, tmp, &vgic_cpu->ap_list_head, ap_list )
> +    {
> +        struct vcpu *target_vcpu, *vcpuA, *vcpuB;
> +
> +        spin_lock(&irq->irq_lock);
> +
> +        BUG_ON(vcpu != irq->vcpu);
> +
> +        target_vcpu = vgic_target_oracle(irq);
> +
> +        if ( !target_vcpu )
> +        {
> +            /*
> +             * We don't need to process this interrupt any
> +             * further, move it off the list.
> +             */
> +            list_del(&irq->ap_list);
> +            irq->vcpu = NULL;
> +            spin_unlock(&irq->irq_lock);
> +
> +            /*
> +             * This vgic_put_irq call matches the
> +             * vgic_get_irq_kref in vgic_queue_irq_unlock,
> +             * where we added the LPI to the ap_list. As
> +             * we remove the irq from the list, we drop
> +             * also drop the refcount.
> +             */
> +            vgic_put_irq(vcpu->domain, irq);
> +            continue;
> +        }
> +
> +        if ( target_vcpu == vcpu )
> +        {
> +            /* We're on the right CPU */
> +            spin_unlock(&irq->irq_lock);
> +            continue;
> +        }
> +
> +        /* This interrupt looks like it has to be migrated. */
> +
> +        spin_unlock(&irq->irq_lock);
> +        spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
> +
> +        /*
> +         * Ensure locking order by always locking the smallest
> +         * ID first.
> +         */
> +        if ( vcpu->vcpu_id < target_vcpu->vcpu_id )
> +        {
> +            vcpuA = vcpu;
> +            vcpuB = target_vcpu;
> +        }
> +        else
> +        {
> +            vcpuA = target_vcpu;
> +            vcpuB = vcpu;
> +        }
> +
> +        spin_lock_irqsave(&vcpuA->arch.vgic.ap_list_lock, flags);
> +        spin_lock(&vcpuB->arch.vgic.ap_list_lock);
> +        spin_lock(&irq->irq_lock);
> +
> +        /*
> +         * If the affinity has been preserved, move the
> +         * interrupt around. Otherwise, it means things have
> +         * changed while the interrupt was unlocked, and we
> +         * need to replay this.
> +         *
> +         * In all cases, we cannot trust the list not to have
> +         * changed, so we restart from the beginning.
> +         */
> +        if ( target_vcpu == vgic_target_oracle(irq) )
> +        {
> +            struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic;
> +
> +            list_del(&irq->ap_list);
> +            irq->vcpu = target_vcpu;
> +            list_add_tail(&irq->ap_list, &new_cpu->ap_list_head);
> +        }
> +
> +        spin_unlock(&irq->irq_lock);
> +        spin_unlock(&vcpuB->arch.vgic.ap_list_lock);
> +        spin_unlock_irqrestore(&vcpuA->arch.vgic.ap_list_lock, flags);
> +        goto retry;
> +    }
> +
> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
> +}
> +
> +static void vgic_fold_lr_state(struct vcpu *vcpu)
> +{
> +}
> +
> +/* Requires the irq_lock to be held. */
> +static void vgic_populate_lr(struct vcpu *vcpu,
> +                             struct vgic_irq *irq, int lr)
> +{
> +    ASSERT(spin_is_locked(&irq->irq_lock));
> +}
> +
> +static void vgic_set_underflow(struct vcpu *vcpu)
> +{
> +    ASSERT(vcpu == current);
> +
> +    gic_hw_ops->update_hcr_status(GICH_HCR_UIE, true);
> +}
> +
> +/* Requires the ap_list_lock to be held. */
> +static int compute_ap_list_depth(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +    struct vgic_irq *irq;
> +    int count = 0;
> +
> +    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
> +    {
> +        spin_lock(&irq->irq_lock);
> +        /* GICv2 SGIs can count for more than one... */
> +        if ( vgic_irq_is_sgi(irq->intid) && irq->source )
> +            count += hweight8(irq->source);

Why is this done?


> +        else
> +            count++;
> +        spin_unlock(&irq->irq_lock);
> +    }
> +    return count;
> +}
> +
> +/* Requires the VCPU's ap_list_lock to be held. */
> +static void vgic_flush_lr_state(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +    struct vgic_irq *irq;
> +    int count = 0;
> +
> +    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
> +
> +    if ( compute_ap_list_depth(vcpu) > gic_get_nr_lrs() )
> +        vgic_sort_ap_list(vcpu);
> +
> +    list_for_each_entry( irq, &vgic_cpu->ap_list_head, ap_list )
> +    {
> +        spin_lock(&irq->irq_lock);
> +
> +        if ( likely(vgic_target_oracle(irq) == vcpu) )
> +            vgic_populate_lr(vcpu, irq, count++);
> +
> +        spin_unlock(&irq->irq_lock);
> +
> +        if ( count == gic_get_nr_lrs() )
> +        {
> +            if ( !list_is_last(&irq->ap_list, &vgic_cpu->ap_list_head) )
> +                vgic_set_underflow(vcpu);
> +            break;
> +        }
> +    }
> +
> +    vcpu->arch.vgic.used_lrs = count;
> +}
> +
> +/**
> + * vgic_sync_from_lrs() - Update VGIC state from hardware after a guest's run.
> + * @vcpu: the VCPU for which to transfer from the LRs to the IRQ list.
> + *
> + * Sync back the hardware VGIC state after the guest has run, into our
> + * VGIC emulation structures, It reads the LRs and updates the respective
> + * struct vgic_irq, taking level/edge into account.
> + * This is the high level function which takes care of the conditions,
> + * also bails out early if there were no interrupts queued.
> + * Was: kvm_vgic_sync_hwstate()
> + */
> +void vgic_sync_from_lrs(struct vcpu *vcpu)
> +{
> +    /* An empty ap_list_head implies used_lrs == 0 */
> +    if ( list_empty(&vcpu->arch.vgic.ap_list_head) )
> +        return;
> +
> +    vgic_fold_lr_state(vcpu);
> +
> +    vgic_prune_ap_list(vcpu);
> +}
> +
> +/**
> + * vgic_sync_to_lrs() - flush emulation state into the hardware on guest entry
> + *
> + * Before we enter a guest, we have to translate the virtual GIC state of a
> + * VCPU into the GIC virtualization hardware registers, namely the LRs.
> + * This is the high level function which takes care about the conditions
> + * and the locking, also bails out early if there are no interrupts queued.
> + * Was: kvm_vgic_flush_hwstate()
> + */
> +void vgic_sync_to_lrs(void)
> +{
> +    /*
> +     * If there are no virtual interrupts active or pending for this
> +     * VCPU, then there is no work to do and we can bail out without
> +     * taking any lock.  There is a potential race with someone injecting
> +     * interrupts to the VCPU, but it is a benign race as the VCPU will
> +     * either observe the new interrupt before or after doing this check,
> +     * and introducing additional synchronization mechanism doesn't change
> +     * this.
> +     */
> +    if ( list_empty(&current->arch.vgic.ap_list_head) )
> +        return;
> +
> +    ASSERT(!local_irq_is_enabled());
> +
> +    spin_lock(&current->arch.vgic.ap_list_lock);
> +    vgic_flush_lr_state(current);
> +    spin_unlock(&current->arch.vgic.ap_list_lock);
> +}
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index f9e2eeb2d6..f530cfa078 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -17,6 +17,8 @@
>  #ifndef __XEN_ARM_VGIC_VGIC_H__
>  #define __XEN_ARM_VGIC_VGIC_H__
>  
> +#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
> +
>  static inline bool irq_is_pending(struct vgic_irq *irq)
>  {
>      if ( irq->config == VGIC_CONFIG_EDGE )

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq
  2018-03-22 11:15     ` Andre Przywara
@ 2018-03-26 23:34       ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 23:34 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

[-- Attachment #1: Type: TEXT/PLAIN, Size: 3203 bytes --]

On Thu, 22 Mar 2018, Andre Przywara wrote:
> Hi,
> 
> On 22/03/18 03:52, Julien Grall wrote:
> > Hi Andre,
> > 
> > On 03/21/2018 04:32 PM, Andre Przywara wrote:
> >> Tell Xen whether a particular VCPU has an IRQ that needs handling
> >> in the guest. This is used to decide whether a VCPU is runnable or
> >> if a hypercall should be preempted to let the guest handle the IRQ.
> >>
> >> This is based on Linux commit 90eee56c5f90, written by Eric Auger.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> >> ---
> >> Changelog v2 ... v3:
> >> - adjust vgic_vcpu_pending_irq() to return integers, not false/true
> > 
> > I would have preferred to have the return switch to bool instead. I
> > guess this can be done on a follow-up. With one comment below:
> 
> I did that originally, but then you meanwhile merged that first patch
> already. So I didn't want to add another patch to this series.
> I am fine with changing this afterwards, probably as part of a fixup series.
> 
> > Reviewed-by: Julien Grall <julien.grall@arm.com>
> 
> Thanks!

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> Cheers,
> Andre.
> 
> >>
> >> Changelog v1 ... v2:
> >> - adjust to new vgic_vcpu_pending_irq() prototype, drop wrapper
> >>
> >>   xen/arch/arm/vgic/vgic.c | 37 +++++++++++++++++++++++++++++++++++++
> >>   1 file changed, 37 insertions(+)
> >>
> >> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> >> index 2fa595f4f7..925cda4580 100644
> >> --- a/xen/arch/arm/vgic/vgic.c
> >> +++ b/xen/arch/arm/vgic/vgic.c
> >> @@ -647,6 +647,43 @@ void vgic_sync_to_lrs(void)
> >>       gic_hw_ops->update_hcr_status(GICH_HCR_EN, 1);
> >>   }
> >>   +/**
> >> + * vgic_vcpu_pending_irq() - determine if interrupts need to be injected
> >> + * @vcpu: The vCPU on which to check for interrupts.
> >> + *
> >> + * Checks whether there is an interrupt on the given VCPU which needs
> >> + * handling in the guest. This requires at least one IRQ to be pending
> >> + * and enabled.
> >> + *
> >> + * Returns: 1 if the guest should run to handle interrupts, 0 otherwise.
> > 
> > NIT: Because of "ret = irq_is_pending(irq) && irq->enabled", you will
> > return a non-zero value if the guest should run to handle interrupts.
> > 
> >> + */
> >> +int vgic_vcpu_pending_irq(struct vcpu *vcpu)
> >> +{
> >> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> >> +    struct vgic_irq *irq;
> >> +    unsigned long flags;
> >> +    int ret = 0;
> >> +
> >> +    if ( !vcpu->domain->arch.vgic.enabled )
> >> +        return 0;
> >> +
> >> +    spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
> >> +
> >> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
> >> +    {
> >> +        spin_lock(&irq->irq_lock);
> >> +        ret = irq_is_pending(irq) && irq->enabled;
> >> +        spin_unlock(&irq->irq_lock);
> >> +
> >> +        if ( ret )
> >> +            break;
> >> +    }
> >> +
> >> +    spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
> >> +
> >> +    return ret;
> >> +}
> >> +
> >>   /*
> >>    * Local variables:
> >>    * mode: C
> >>
> > 
> > Cheers,
> > 
> 

[-- Attachment #2: Type: text/plain, Size: 157 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs()
  2018-03-21 16:32 ` [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs() Andre Przywara
@ 2018-03-26 23:46   ` Stefano Stabellini
  2018-03-28 18:47   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-26 23:46 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> When a VCPU moves to another CPU, we need to adjust the target affinity
> of any hardware mapped vIRQs, to observe our "physical-follows-virtual"
> policy.
> Implement arch_move_irqs() to adjust the physical affinity of all hardware
> mapped vIRQs targetting this VCPU.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>

> ---
>  xen/arch/arm/vgic/vgic.c | 39 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 39 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index ffab0b2635..23b8abfc5e 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -791,6 +791,45 @@ void gic_dump_vgic_info(struct vcpu *v)
>      spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
>  }
>  
> +/**
> + * arch_move_irqs() - migrate the physical affinity of hardware mapped vIRQs
> + * @v:  the vCPU, already assigned to the new pCPU
> + *
> + * arch_move_irqs() updates the physical affinity of all virtual IRQs
> + * targetting this given vCPU. This only affects hardware mapped IRQs. The
> + * new pCPU to target is already set in v->processor.
> + * This is called by the core code after a vCPU has been migrated to a new
> + * physical CPU.
> + */
> +void arch_move_irqs(struct vcpu *v)
> +{
> +    struct domain *d = v->domain;
> +    unsigned int i;
> +
> +    /* We only target SPIs with this function */
> +    for ( i = 0; i < d->arch.vgic.nr_spis; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(d, NULL, i + VGIC_NR_PRIVATE_IRQS);
> +        unsigned long flags;
> +
> +        if ( !irq )
> +            continue;
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        /* only vIRQs that are not on a vCPU yet , but targetting this vCPU */
> +        if ( irq->hw && !irq->vcpu && irq->target_vcpu == v)
> +        {
> +            irq_desc_t *desc = irq_to_desc(irq->hwintid);
> +
> +            irq_set_affinity(desc, cpumask_of(v->processor));
> +        }
> +
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +        vgic_put_irq(d, irq);
> +    }
> +}
> +
>  struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>                                        unsigned int virq)
>  {
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 24/39] ARM: new VGIC: Add TARGET registers handlers
  2018-03-21 16:32 ` [PATCH v3 24/39] ARM: new VGIC: Add TARGET " Andre Przywara
@ 2018-03-27  0:24   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27  0:24 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The target register handlers are v2 emulation specific, so their
> implementation lives entirely in vgic-mmio-v2.c.
> We copy the old VGIC behaviour of assigning an IRQ to the first VCPU
> set in the target mask instead of making it possibly pending on
> multiple VCPUs.
> We update the physical affinity of a hardware mapped vIRQ on the way.
> 
> This is based on Linux commit 2c234d6f1826, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/vgic/vgic-mmio-v2.c | 59 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 58 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index a28d0e459b..b333de9ed7 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -81,6 +81,63 @@ static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
>      }
>  }
>  
> +static unsigned long vgic_mmio_read_target(struct vcpu *vcpu,
> +                                           paddr_t addr, unsigned int len)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> +    uint32_t val = 0;
> +    unsigned int i;
> +
> +    for ( i = 0; i < len; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        val |= (uint32_t)irq->targets << (i * 8);
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +
> +    return val;
> +}
> +
> +static void vgic_mmio_write_target(struct vcpu *vcpu,
> +                                   paddr_t addr, unsigned int len,
> +                                   unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> +    uint8_t cpu_mask = GENMASK(vcpu->domain->max_vcpus - 1, 0);
> +    unsigned int i;
> +    unsigned long flags;
> +
> +    /* GICD_ITARGETSR[0-7] are read-only */
> +    if ( intid < VGIC_NR_PRIVATE_IRQS )
> +        return;
> +
> +    for ( i = 0; i < len; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, NULL, intid + i);
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        irq->targets = (val >> (i * 8)) & cpu_mask;
> +        if ( irq->targets )
> +        {
> +            irq->target_vcpu = vcpu->domain->vcpu[ffs(irq->targets) - 1];
> +            if ( irq->hw )
> +            {
> +                struct irq_desc *desc = irq_to_desc(irq->hwintid);
> +
> +                irq_set_affinity(desc, cpumask_of(irq->target_vcpu->processor));
> +            }
> +        }
> +        else
> +            irq->target_vcpu = NULL;
> +
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>      REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>          vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
> @@ -110,7 +167,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +        vgic_mmio_read_target, vgic_mmio_write_target, 8,
>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
>          vgic_mmio_read_config, vgic_mmio_write_config, 2,
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly
  2018-03-26 20:28   ` Stefano Stabellini
@ 2018-03-27 13:06     ` Andre Przywara
  2018-03-27 18:17       ` Stefano Stabellini
  0 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-27 13:06 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 26/03/18 21:28, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> The ARM Generic Timer uses a level-sensitive interrupt semantic. We
>> easily catch when the line goes high, as this triggers the hardware IRQ.
>> However we also have to keep track of when the line lowers, as the
>> emulation depends on it: Upon entering the guest, the new VGIC will
>> *clear* the virtual interrupt line, so it needs to re-sample the actual
>> state after returning from the guest.
>> So we have to sync the state of the interrupt condition at certain
>> points to catch when the line goes low and we can remove the vtimer vIRQ
>> from the vGIC (and the LR).
>> The VGIC in Xen so far only implemented edge triggered vIRQs, really, so
>> we need to add new functionality to re-sample the interrupt state.
>> Do this only when the new VGIC is in use.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>> Changelog v2 ... v3:
>> - move vtimer_sync() from time.c into vtimer.c
>> - rename function to vtimer_update_irqs()
>> - refactor functionality into new static function, to ...
>> - handle physical timer as well
>> - extending comments
>>
>> Changelog v1 ... v2:
>> - restrict to new VGIC
>> - add TODO: comment
>>
>>  xen/arch/arm/traps.c         | 11 ++++++++++
>>  xen/arch/arm/vtimer.c        | 49 ++++++++++++++++++++++++++++++++++++++++++++
>>  xen/include/asm-arm/vtimer.h |  1 +
>>  3 files changed, 61 insertions(+)
>>
>> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
>> index 7411bff7a7..2638446693 100644
>> --- a/xen/arch/arm/traps.c
>> +++ b/xen/arch/arm/traps.c
>> @@ -2024,6 +2024,17 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
>>          if ( current->arch.hcr_el2 & HCR_VA )
>>              current->arch.hcr_el2 = READ_SYSREG(HCR_EL2);
>>  
>> +#ifdef CONFIG_NEW_VGIC
>> +        /*
>> +         * We need to update the state of our emulated devices using level
>> +         * triggered interrupts before syncing back the VGIC state.
>> +         *
>> +         * TODO: Investigate whether this is necessary to do on every
>> +         * trap and how it can be optimised.
>> +         */
>> +        vtimer_update_irqs(current);
>> +#endif
>> +
>>          vgic_sync_from_lrs(current);
>>      }
>>  }
>> diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c
>> index 8164f6c7f1..c99dd237d1 100644
>> --- a/xen/arch/arm/vtimer.c
>> +++ b/xen/arch/arm/vtimer.c
>> @@ -334,6 +334,55 @@ bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr)
>>      }
>>  }
>>  
>> +static void vtimer_update_irq(struct vcpu *v, struct vtimer *vtimer,
>> +                              uint32_t vtimer_ctl)
>> +{
>> +    bool level;
>> +
>> +    /* Filter for the three bits that determine the status of the timer */
>> +    vtimer_ctl &= (CNTx_CTL_ENABLE | CNTx_CTL_PENDING | CNTx_CTL_MASK);
>> +
>> +    /* The level is high if the timer is pending and enabled, but not masked. */
>> +    level = (vtimer_ctl == (CNTx_CTL_ENABLE | CNTx_CTL_PENDING));
>> +
>> +    /*
>> +     * This is mostly here to *lower* the virtual interrupt line if the timer
>> +     * is no longer pending.
>> +     * We would have injected an IRQ already via SOFTIRQ when the timer expired.
>> +     * Doing it here again is basically a NOP if the line was already high.
>> +     */
>> +    vgic_inject_irq(v->domain, v, vtimer->irq, level);
>> +}
>> +
>> +/**
>> + * vtimer_update_irqs() - update the virtual timers' IRQ lines after a guest run
>> + * @vcpu: The VCPU to sync the timer state
>> + *
>> + * After returning from a guest, update the state of the timers' virtual
>> + * interrupt lines, to model the level triggered interrupts correctly.
>> + * If the guest has handled a timer interrupt, the virtual interrupt line
>> + * needs to be lowered explicitly. vgic_inject_irq() takes care of that.
>> + */
>> +void vtimer_update_irqs(struct vcpu *v)
>> +{
>> +    /*
>> +     * For the virtual timer we read the current state from the hardware.
>> +     * Technically we should keep the CNTx_CTL_MASK bit here, to catch if
>> +     * the timer interrupt is masked. However Xen *always* masks the timer
>> +     * upon entering the hypervisor, leaving it up to the guest to un-mask it.
>> +     * So we would always read a "low" level, despite the condition being
>> +     * actually "high".  Ignoring the mask bit solves this (for now).
>> +     *
>> +     * TODO: The proper fix for this is to make vtimer vIRQ hardware mapped,
>> +     * but this requires reworking the arch timer to implement this.
>> +     */
>> +    vtimer_update_irq(v, &v->arch.virt_timer,
>> +                      READ_SYSREG32(CNTV_CTL_EL0) & ~CNTx_CTL_MASK);
> 
> Yes, but won't this have the opposite effect? Meaning that it will
> always read as "high" for the virtual timer (because we remove the MASK
> and that is the only thing that can cause a "low" read in
> vtimer_update_irq if it's enabled and pending)?

What we want to know here is the status of the interrupt line of the
virtual timer. We don't know if it's still pending or not. So we are
very much interested in the pending bit of CNTV_CTL_EL0.
We could read the distributor's ISPENDR register as well, but this is
more costly.

> It seems to me that it would be better to remove the update of the
> virtual timer -- this seems to have the potential of causing problems.

Removing this makes Dom0 hang very early. The reason is that in that
case we never clear the line_level in the vtimer's struct vgic_irq:
When the h/w IRQ fires, we set line_level by injecting the corresponding
virtual IRQ. But if the emulated line_level is still high,
vgic_inject_irq() will bail out early, as making an IRQ pending when it
is already pending is a NOP, so vgic_validate_injection() denies that case.

Properly emulating the actual state of a virtual level triggered
interrupt line is something we were totally ignoring so far, because we
only dealt with edge interrupts. In case of the timer and also the event
channel this is wrong, as both devices are actually using level
triggered interrupts semantics.

Cheers,
Andre.

>> +    /* For the physical timer we rely on our emulated state. */
>> +    vtimer_update_irq(v, &v->arch.phys_timer, v->arch.phys_timer.ctl);
>> +}
>> +
>>  /*
>>   * Local variables:
>>   * mode: C
>> diff --git a/xen/include/asm-arm/vtimer.h b/xen/include/asm-arm/vtimer.h
>> index 5aaddc6f63..91d88b377f 100644
>> --- a/xen/include/asm-arm/vtimer.h
>> +++ b/xen/include/asm-arm/vtimer.h
>> @@ -27,6 +27,7 @@ extern bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr);
>>  extern int virt_timer_save(struct vcpu *v);
>>  extern int virt_timer_restore(struct vcpu *v);
>>  extern void vcpu_timer_destroy(struct vcpu *v);
>> +void vtimer_update_irqs(struct vcpu *v);
>>  
>>  #endif
>>  
>> -- 
>> 2.14.1
>>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework
  2018-03-26 21:30   ` Stefano Stabellini
@ 2018-03-27 13:23     ` Andre Przywara
  2018-03-27 18:55       ` Stefano Stabellini
  0 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-27 13:23 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 26/03/18 22:30, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> Implement the framework for syncing IRQs between our emulation and the
>> list registers, which represent the guest's view of IRQs.
>> This is done in vgic_sync_from_lrs() and vgic_sync_to_lrs(), which
>> get called on guest entry and exit, respectively.
>> The code talking to the actual GICv2/v3 hardware is added in the
>> following patches.
>>
>> This is based on Linux commit 0919e84c0fc1, written by Marc Zyngier.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> 
> Just one question below, but the code looks nice
> 
> 
>> ---
>> Changelog v2 ... v3:
>> - replace "true" instead of "1" for the boolean parameter
>>
>> Changelog v1 ... v2:
>> - make functions void
>> - do underflow setting directly (no v2/v3 indirection)
>> - fix multiple SGIs injections (as the late Linux bugfix)
>>
>>  xen/arch/arm/vgic/vgic.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++
>>  xen/arch/arm/vgic/vgic.h |   2 +
>>  2 files changed, 234 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index ee0de8d2e0..52e1669888 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -409,6 +409,238 @@ void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,

....

>> +/* Requires the ap_list_lock to be held. */
>> +static int compute_ap_list_depth(struct vcpu *vcpu)
>> +{
>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
>> +    struct vgic_irq *irq;
>> +    int count = 0;
>> +
>> +    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
>> +
>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>> +    {
>> +        spin_lock(&irq->irq_lock);
>> +        /* GICv2 SGIs can count for more than one... */
>> +        if ( vgic_irq_is_sgi(irq->intid) && irq->source )
>> +            count += hweight8(irq->source);
> 
> Why is this done?

GICv2 SGIs always have a source CPU ID connected to them. So if two CPUs
signal another CPU at the same time, there are *two* distinct SGIs, with
two different source IDs. This is an architectural feature of GICv2, so
we have to properly emulate this.
Despite them being edge triggered IRQs, we cannot coalesce them in this
case.

Cheers,
Andre.

>> +        else
>> +            count++;
>> +        spin_unlock(&irq->irq_lock);
>> +    }
>> +    return count;
>> +}
>> +

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly
  2018-03-27 13:06     ` Andre Przywara
@ 2018-03-27 18:17       ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 18:17 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Tue, 27 Mar 2018, Andre Przywara wrote:
> Hi,
> 
> On 26/03/18 21:28, Stefano Stabellini wrote:
> > On Wed, 21 Mar 2018, Andre Przywara wrote:
> >> The ARM Generic Timer uses a level-sensitive interrupt semantic. We
> >> easily catch when the line goes high, as this triggers the hardware IRQ.
> >> However we also have to keep track of when the line lowers, as the
> >> emulation depends on it: Upon entering the guest, the new VGIC will
> >> *clear* the virtual interrupt line, so it needs to re-sample the actual
> >> state after returning from the guest.
> >> So we have to sync the state of the interrupt condition at certain
> >> points to catch when the line goes low and we can remove the vtimer vIRQ
> >> from the vGIC (and the LR).
> >> The VGIC in Xen so far only implemented edge triggered vIRQs, really, so
> >> we need to add new functionality to re-sample the interrupt state.
> >> Do this only when the new VGIC is in use.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> >> ---
> >> Changelog v2 ... v3:
> >> - move vtimer_sync() from time.c into vtimer.c
> >> - rename function to vtimer_update_irqs()
> >> - refactor functionality into new static function, to ...
> >> - handle physical timer as well
> >> - extending comments
> >>
> >> Changelog v1 ... v2:
> >> - restrict to new VGIC
> >> - add TODO: comment
> >>
> >>  xen/arch/arm/traps.c         | 11 ++++++++++
> >>  xen/arch/arm/vtimer.c        | 49 ++++++++++++++++++++++++++++++++++++++++++++
> >>  xen/include/asm-arm/vtimer.h |  1 +
> >>  3 files changed, 61 insertions(+)
> >>
> >> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> >> index 7411bff7a7..2638446693 100644
> >> --- a/xen/arch/arm/traps.c
> >> +++ b/xen/arch/arm/traps.c
> >> @@ -2024,6 +2024,17 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
> >>          if ( current->arch.hcr_el2 & HCR_VA )
> >>              current->arch.hcr_el2 = READ_SYSREG(HCR_EL2);
> >>  
> >> +#ifdef CONFIG_NEW_VGIC
> >> +        /*
> >> +         * We need to update the state of our emulated devices using level
> >> +         * triggered interrupts before syncing back the VGIC state.
> >> +         *
> >> +         * TODO: Investigate whether this is necessary to do on every
> >> +         * trap and how it can be optimised.
> >> +         */
> >> +        vtimer_update_irqs(current);
> >> +#endif
> >> +
> >>          vgic_sync_from_lrs(current);
> >>      }
> >>  }
> >> diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c
> >> index 8164f6c7f1..c99dd237d1 100644
> >> --- a/xen/arch/arm/vtimer.c
> >> +++ b/xen/arch/arm/vtimer.c
> >> @@ -334,6 +334,55 @@ bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr)
> >>      }
> >>  }
> >>  
> >> +static void vtimer_update_irq(struct vcpu *v, struct vtimer *vtimer,
> >> +                              uint32_t vtimer_ctl)
> >> +{
> >> +    bool level;
> >> +
> >> +    /* Filter for the three bits that determine the status of the timer */
> >> +    vtimer_ctl &= (CNTx_CTL_ENABLE | CNTx_CTL_PENDING | CNTx_CTL_MASK);
> >> +
> >> +    /* The level is high if the timer is pending and enabled, but not masked. */
> >> +    level = (vtimer_ctl == (CNTx_CTL_ENABLE | CNTx_CTL_PENDING));
> >> +
> >> +    /*
> >> +     * This is mostly here to *lower* the virtual interrupt line if the timer
> >> +     * is no longer pending.
> >> +     * We would have injected an IRQ already via SOFTIRQ when the timer expired.
> >> +     * Doing it here again is basically a NOP if the line was already high.
> >> +     */
> >> +    vgic_inject_irq(v->domain, v, vtimer->irq, level);
> >> +}
> >> +
> >> +/**
> >> + * vtimer_update_irqs() - update the virtual timers' IRQ lines after a guest run
> >> + * @vcpu: The VCPU to sync the timer state
> >> + *
> >> + * After returning from a guest, update the state of the timers' virtual
> >> + * interrupt lines, to model the level triggered interrupts correctly.
> >> + * If the guest has handled a timer interrupt, the virtual interrupt line
> >> + * needs to be lowered explicitly. vgic_inject_irq() takes care of that.
> >> + */
> >> +void vtimer_update_irqs(struct vcpu *v)
> >> +{
> >> +    /*
> >> +     * For the virtual timer we read the current state from the hardware.
> >> +     * Technically we should keep the CNTx_CTL_MASK bit here, to catch if
> >> +     * the timer interrupt is masked. However Xen *always* masks the timer
> >> +     * upon entering the hypervisor, leaving it up to the guest to un-mask it.
> >> +     * So we would always read a "low" level, despite the condition being
> >> +     * actually "high".  Ignoring the mask bit solves this (for now).
> >> +     *
> >> +     * TODO: The proper fix for this is to make vtimer vIRQ hardware mapped,
> >> +     * but this requires reworking the arch timer to implement this.
> >> +     */
> >> +    vtimer_update_irq(v, &v->arch.virt_timer,
> >> +                      READ_SYSREG32(CNTV_CTL_EL0) & ~CNTx_CTL_MASK);
> > 
> > Yes, but won't this have the opposite effect? Meaning that it will
> > always read as "high" for the virtual timer (because we remove the MASK
> > and that is the only thing that can cause a "low" read in
> > vtimer_update_irq if it's enabled and pending)?
> 
> What we want to know here is the status of the interrupt line of the
> virtual timer. We don't know if it's still pending or not. So we are
> very much interested in the pending bit of CNTV_CTL_EL0.
> We could read the distributor's ISPENDR register as well, but this is
> more costly.
> 
> > It seems to me that it would be better to remove the update of the
> > virtual timer -- this seems to have the potential of causing problems.
> 
> Removing this makes Dom0 hang very early. The reason is that in that
> case we never clear the line_level in the vtimer's struct vgic_irq:
> When the h/w IRQ fires, we set line_level by injecting the corresponding
> virtual IRQ. But if the emulated line_level is still high,
> vgic_inject_irq() will bail out early, as making an IRQ pending when it
> is already pending is a NOP, so vgic_validate_injection() denies that case.
> 
> Properly emulating the actual state of a virtual level triggered
> interrupt line is something we were totally ignoring so far, because we
> only dealt with edge interrupts. In case of the timer and also the event
> channel this is wrong, as both devices are actually using level
> triggered interrupts semantics.

OK, thanks for the explanation

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> >> +    /* For the physical timer we rely on our emulated state. */
> >> +    vtimer_update_irq(v, &v->arch.phys_timer, v->arch.phys_timer.ctl);
> >> +}
> >> +
> >>  /*
> >>   * Local variables:
> >>   * mode: C
> >> diff --git a/xen/include/asm-arm/vtimer.h b/xen/include/asm-arm/vtimer.h
> >> index 5aaddc6f63..91d88b377f 100644
> >> --- a/xen/include/asm-arm/vtimer.h
> >> +++ b/xen/include/asm-arm/vtimer.h
> >> @@ -27,6 +27,7 @@ extern bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr);
> >>  extern int virt_timer_save(struct vcpu *v);
> >>  extern int virt_timer_restore(struct vcpu *v);
> >>  extern void vcpu_timer_destroy(struct vcpu *v);
> >> +void vtimer_update_irqs(struct vcpu *v);
> >>  
> >>  #endif
> >>  
> >> -- 
> >> 2.14.1
> >>
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework
  2018-03-27 13:23     ` Andre Przywara
@ 2018-03-27 18:55       ` Stefano Stabellini
  2018-03-27 19:20         ` Stefano Stabellini
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 18:55 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Tue, 27 Mar 2018, Andre Przywara wrote:
> Hi,
> 
> On 26/03/18 22:30, Stefano Stabellini wrote:
> > On Wed, 21 Mar 2018, Andre Przywara wrote:
> >> Implement the framework for syncing IRQs between our emulation and the
> >> list registers, which represent the guest's view of IRQs.
> >> This is done in vgic_sync_from_lrs() and vgic_sync_to_lrs(), which
> >> get called on guest entry and exit, respectively.
> >> The code talking to the actual GICv2/v3 hardware is added in the
> >> following patches.
> >>
> >> This is based on Linux commit 0919e84c0fc1, written by Marc Zyngier.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> > 
> > Just one question below, but the code looks nice
> > 
> > 
> >> ---
> >> Changelog v2 ... v3:
> >> - replace "true" instead of "1" for the boolean parameter
> >>
> >> Changelog v1 ... v2:
> >> - make functions void
> >> - do underflow setting directly (no v2/v3 indirection)
> >> - fix multiple SGIs injections (as the late Linux bugfix)
> >>
> >>  xen/arch/arm/vgic/vgic.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++
> >>  xen/arch/arm/vgic/vgic.h |   2 +
> >>  2 files changed, 234 insertions(+)
> >>
> >> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> >> index ee0de8d2e0..52e1669888 100644
> >> --- a/xen/arch/arm/vgic/vgic.c
> >> +++ b/xen/arch/arm/vgic/vgic.c
> >> @@ -409,6 +409,238 @@ void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,
> 
> ....
> 
> >> +/* Requires the ap_list_lock to be held. */
> >> +static int compute_ap_list_depth(struct vcpu *vcpu)
> >> +{
> >> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> >> +    struct vgic_irq *irq;
> >> +    int count = 0;
> >> +
> >> +    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
> >> +
> >> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
> >> +    {
> >> +        spin_lock(&irq->irq_lock);
> >> +        /* GICv2 SGIs can count for more than one... */
> >> +        if ( vgic_irq_is_sgi(irq->intid) && irq->source )
> >> +            count += hweight8(irq->source);
> > 
> > Why is this done?
> 
> GICv2 SGIs always have a source CPU ID connected to them. So if two CPUs
> signal another CPU at the same time, there are *two* distinct SGIs, with
> two different source IDs. This is an architectural feature of GICv2, so
> we have to properly emulate this.
> Despite them being edge triggered IRQs, we cannot coalesce them in this
> case.

I went through the whole lifecycle of SGIs with the new vgic and it is
quite different from before, but it makes sense to me now.

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> Cheers,
> Andre.
> 
> >> +        else
> >> +            count++;
> >> +        spin_unlock(&irq->irq_lock);
> >> +    }
> >> +    return count;
> >> +}
> >> +

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework
  2018-03-27 18:55       ` Stefano Stabellini
@ 2018-03-27 19:20         ` Stefano Stabellini
  2018-03-27 22:13           ` André Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 19:20 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Andre Przywara, Julien Grall, xen-devel

On Tue, 27 Mar 2018, Stefano Stabellini wrote:
> On Tue, 27 Mar 2018, Andre Przywara wrote:
> > Hi,
> > 
> > On 26/03/18 22:30, Stefano Stabellini wrote:
> > > On Wed, 21 Mar 2018, Andre Przywara wrote:
> > >> Implement the framework for syncing IRQs between our emulation and the
> > >> list registers, which represent the guest's view of IRQs.
> > >> This is done in vgic_sync_from_lrs() and vgic_sync_to_lrs(), which
> > >> get called on guest entry and exit, respectively.
> > >> The code talking to the actual GICv2/v3 hardware is added in the
> > >> following patches.
> > >>
> > >> This is based on Linux commit 0919e84c0fc1, written by Marc Zyngier.
> > >>
> > >> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> > > 
> > > Just one question below, but the code looks nice
> > > 
> > > 
> > >> ---
> > >> Changelog v2 ... v3:
> > >> - replace "true" instead of "1" for the boolean parameter
> > >>
> > >> Changelog v1 ... v2:
> > >> - make functions void
> > >> - do underflow setting directly (no v2/v3 indirection)
> > >> - fix multiple SGIs injections (as the late Linux bugfix)
> > >>
> > >>  xen/arch/arm/vgic/vgic.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++
> > >>  xen/arch/arm/vgic/vgic.h |   2 +
> > >>  2 files changed, 234 insertions(+)
> > >>
> > >> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> > >> index ee0de8d2e0..52e1669888 100644
> > >> --- a/xen/arch/arm/vgic/vgic.c
> > >> +++ b/xen/arch/arm/vgic/vgic.c
> > >> @@ -409,6 +409,238 @@ void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,
> > 
> > ....
> > 
> > >> +/* Requires the ap_list_lock to be held. */
> > >> +static int compute_ap_list_depth(struct vcpu *vcpu)
> > >> +{
> > >> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> > >> +    struct vgic_irq *irq;
> > >> +    int count = 0;
> > >> +
> > >> +    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
> > >> +
> > >> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
> > >> +    {
> > >> +        spin_lock(&irq->irq_lock);
> > >> +        /* GICv2 SGIs can count for more than one... */
> > >> +        if ( vgic_irq_is_sgi(irq->intid) && irq->source )
> > >> +            count += hweight8(irq->source);
> > > 
> > > Why is this done?
> > 
> > GICv2 SGIs always have a source CPU ID connected to them. So if two CPUs
> > signal another CPU at the same time, there are *two* distinct SGIs, with
> > two different source IDs. This is an architectural feature of GICv2, so
> > we have to properly emulate this.
> > Despite them being edge triggered IRQs, we cannot coalesce them in this
> > case.
> 
> I went through the whole lifecycle of SGIs with the new vgic and it is
> quite different from before, but it makes sense to me now.
> 
> Acked-by: Stefano Stabellini <sstabellini@kernel.org>

Actually, I take it back, one more question :-)

I understand that every bit set in irq->source corresponds to a
different interrupt that needs to be injected into the guest. They are
distinct interrupts.

However, compute_ap_list_depth is called to figure out whether the
entries in ap_list overflow the LR registers, and it is never the case
that we write to more than one LR register for a given SGI, even if
irq->source has multiple bit sets, right?

In a concrete example, if we have 3 LR registers and 3 interrupts in
ap_list, one of them is an SGI with multiple irq->source bits, there is
still no need to sort the ap_list, correct?

I think we should remove the special if statement for sgis in
compute_ap_list_depth.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 16/39] ARM: new VGIC: Add MMIO handling framework
  2018-03-21 16:32 ` [PATCH v3 16/39] ARM: new VGIC: Add MMIO handling framework Andre Przywara
@ 2018-03-27 20:07   ` Stefano Stabellini
  2018-03-28  9:28     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 20:07 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Add an MMIO handling framework to the VGIC emulation:
> Each register is described by its offset, size (or number of bits per
> IRQ, if applicable) and the read/write handler functions. We provide
> initialization macros to describe each GIC register later easily.
> 
> Separate dispatch functions for read and write accesses are connected
> to Xen's MMIO handling framework and binary-search for the responsible
> register handler based on the offset address within the region.
> 
> The register handler prototype are courtesy of Christoffer Dall.
> 
> This is based on Linux commit 4493b1c4866a, written by Marc Zyngier.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>

One comment below (the ack still stands anyway).

> ---
>  xen/arch/arm/vgic/vgic-mmio.c | 180 ++++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.h |  89 +++++++++++++++++++++
>  2 files changed, 269 insertions(+)
>  create mode 100644 xen/arch/arm/vgic/vgic-mmio.c
>  create mode 100644 xen/arch/arm/vgic/vgic-mmio.h
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> new file mode 100644
> index 0000000000..866023a84d
> --- /dev/null
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -0,0 +1,180 @@
> +/*
> + * VGIC MMIO handling functions
> + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
> + *
> + * 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.
> + */
> +
> +#include <xen/bitops.h>
> +#include <xen/lib.h>
> +#include <xen/sched.h>
> +#include <asm/new_vgic.h>
> +#include <asm/byteorder.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +unsigned long vgic_mmio_read_raz(struct vcpu *vcpu,
> +                                 paddr_t addr, unsigned int len)
> +{
> +    return 0;
> +}
> +
> +unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
> +                                 paddr_t addr, unsigned int len)
> +{
> +    return -1UL;
> +}
> +
> +void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
> +                        unsigned int len, unsigned long val)
> +{
> +    /* Ignore */
> +}

Would these make sense a static inline?


> +static int match_region(const void *key, const void *elt)
> +{
> +    const unsigned int offset = (unsigned long)key;
> +    const struct vgic_register_region *region = elt;
> +
> +    if ( offset < region->reg_offset )
> +        return -1;
> +
> +    if ( offset >= region->reg_offset + region->len )
> +        return 1;
> +
> +    return 0;
> +}
> +
> +static const struct vgic_register_region *
> +vgic_find_mmio_region(const struct vgic_register_region *regions,
> +                      int nr_regions, unsigned int offset)
> +{
> +    return bsearch((void *)(uintptr_t)offset, regions, nr_regions,
> +                   sizeof(regions[0]), match_region);
> +}
> +
> +static bool check_region(const struct domain *d,
> +                         const struct vgic_register_region *region,
> +                         paddr_t addr, int len)
> +{
> +    unsigned int flags, nr_irqs = d->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +
> +    switch ( len )
> +    {
> +    case sizeof(uint8_t):
> +        flags = VGIC_ACCESS_8bit;
> +        break;
> +    case sizeof(uint32_t):
> +        flags = VGIC_ACCESS_32bit;
> +        break;
> +    case sizeof(uint64_t):
> +        flags = VGIC_ACCESS_64bit;
> +        break;
> +    default:
> +        return false;
> +    }
> +
> +    if ( (region->access_flags & flags) && IS_ALIGNED(addr, len) )
> +    {
> +        if ( !region->bits_per_irq )
> +            return true;
> +
> +        /* Do we access a non-allocated IRQ? */
> +        return VGIC_ADDR_TO_INTID(addr, region->bits_per_irq) < nr_irqs;
> +    }
> +
> +    return false;
> +}
> +
> +static const struct vgic_register_region *
> +vgic_get_mmio_region(struct vcpu *vcpu, struct vgic_io_device *iodev,
> +                     paddr_t addr, unsigned int len)
> +{
> +    const struct vgic_register_region *region;
> +
> +    region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
> +                                   addr - gfn_to_gaddr(iodev->base_fn));
> +    if ( !region || !check_region(vcpu->domain, region, addr, len) )
> +        return NULL;
> +
> +    return region;
> +}
> +
> +static int dispatch_mmio_read(struct vcpu *vcpu, mmio_info_t *info,
> +                              register_t *r, void *priv)
> +{
> +    struct vgic_io_device *iodev = priv;
> +    const struct vgic_register_region *region;
> +    unsigned long data = 0;
> +    paddr_t addr = info->gpa;
> +    int len = 1U << info->dabt.size;
> +
> +    region = vgic_get_mmio_region(vcpu, iodev, addr, len);
> +    if ( !region )
> +    {
> +        memset(r, 0, len);
> +        return 0;
> +    }
> +
> +    switch (iodev->iodev_type)
> +    {
> +    case IODEV_DIST:
> +        data = region->read(vcpu, addr, len);
> +        break;
> +    case IODEV_REDIST:
> +        data = region->read(iodev->redist_vcpu, addr, len);
> +        break;
> +    }
> +
> +    memcpy(r, &data, len);
> +
> +    return 1;
> +}
> +
> +static int dispatch_mmio_write(struct vcpu *vcpu, mmio_info_t *info,
> +                               register_t r, void *priv)
> +{
> +    struct vgic_io_device *iodev = priv;
> +    const struct vgic_register_region *region;
> +    unsigned long data = r;
> +    paddr_t addr = info->gpa;
> +    int len = 1U << info->dabt.size;
> +
> +    region = vgic_get_mmio_region(vcpu, iodev, addr, len);
> +    if ( !region )
> +        return 0;
> +
> +    switch (iodev->iodev_type)
> +    {
> +    case IODEV_DIST:
> +        region->write(vcpu, addr, len, data);
> +        break;
> +    case IODEV_REDIST:
> +        region->write(iodev->redist_vcpu, addr, len, data);
> +        break;
> +    }
> +
> +    return 1;
> +}
> +
> +struct mmio_handler_ops vgic_io_ops = {
> +    .read = dispatch_mmio_read,
> +    .write = dispatch_mmio_write,
> +};
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> new file mode 100644
> index 0000000000..bf062a27ca
> --- /dev/null
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright (C) 2015, 2016 ARM Ltd.
> + *
> + * 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 __XEN_ARM_VGIC_VGIC_MMIO_H__
> +#define __XEN_ARM_VGIC_VGIC_MMIO_H__
> +
> +struct vgic_register_region {
> +    unsigned int reg_offset;
> +    unsigned int len;
> +    unsigned int bits_per_irq;
> +    unsigned int access_flags;
> +    unsigned long (*read)(struct vcpu *vcpu, paddr_t addr,
> +                          unsigned int len);
> +    void (*write)(struct vcpu *vcpu, paddr_t addr,
> +                  unsigned int len, unsigned long val);
> +};
> +
> +extern struct mmio_handler_ops vgic_io_ops;
> +
> +#define VGIC_ACCESS_8bit    1
> +#define VGIC_ACCESS_32bit   2
> +#define VGIC_ACCESS_64bit   4
> +
> +/*
> + * Generate a mask that covers the number of bytes required to address
> + * up to 1024 interrupts, each represented by <bits> bits. This assumes
> + * that <bits> is a power of two.
> + */
> +#define VGIC_ADDR_IRQ_MASK(bits) (((bits) * 1024 / 8) - 1)
> +
> +/*
> + * (addr & mask) gives us the _byte_ offset for the INT ID.
> + * We multiply this by 8 the get the _bit_ offset, then divide this by
> + * the number of bits to learn the actual INT ID.
> + * But instead of a division (which requires a "long long div" implementation),
> + * we shift by the binary logarithm of <bits>.
> + * This assumes that <bits> is a power of two.
> + */
> +#define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
> +                                         8 >> ilog2(bits))
> +
> +/*
> + * Some VGIC registers store per-IRQ information, with a different number
> + * of bits per IRQ. For those registers this macro is used.
> + * The _WITH_LENGTH version instantiates registers with a fixed length
> + * and is mutually exclusive with the _PER_IRQ version.
> + */
> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, rd, wr, bpi, acc)  \
> +    {                                                           \
> +        .reg_offset = off,                                      \
> +        .bits_per_irq = bpi,                                    \
> +        .len = bpi * 1024 / 8,                                  \
> +        .access_flags = acc,                                    \
> +        .read = rd,                                             \
> +        .write = wr,                                            \
> +    }
> +
> +#define REGISTER_DESC_WITH_LENGTH(off, rd, wr, length, acc)     \
> +    {                                                           \
> +        .reg_offset = off,                                      \
> +        .bits_per_irq = 0,                                      \
> +        .len = length,                                          \
> +        .access_flags = acc,                                    \
> +        .read = rd,                                             \
> +        .write = wr,                                            \
> +    }
> +
> +unsigned long vgic_mmio_read_raz(struct vcpu *vcpu,
> +                                 paddr_t addr, unsigned int len);
> +
> +unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
> +                                 paddr_t addr, unsigned int len);
> +
> +void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
> +                        unsigned int len, unsigned long val);
> +
> +#endif
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 17/39] ARM: new VGIC: Add GICv2 MMIO handling framework
  2018-03-21 16:32 ` [PATCH v3 17/39] ARM: new VGIC: Add GICv2 " Andre Przywara
@ 2018-03-27 20:28   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 20:28 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Create vgic-mmio-v2.c to describe GICv2 emulation specific handlers
> using the initializer macros provided by the VGIC MMIO framework.
> Provide a function to register the GICv2 distributor registers to
> the Xen MMIO framework.
> The actual handler functions are still stubs in this patch.
> 
> This is based on Linux commit fb848db39661, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/vgic/vgic-mmio-v2.c | 83 ++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.c    | 25 ++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.h    |  2 +
>  xen/arch/arm/vgic/vgic.h         |  2 +
>  4 files changed, 112 insertions(+)
>  create mode 100644 xen/arch/arm/vgic/vgic-mmio-v2.c
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> new file mode 100644
> index 0000000000..6f10cf16ca
> --- /dev/null
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -0,0 +1,83 @@
> +/*
> + * VGICv2 MMIO handling functions
> + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
> + *
> + * 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.
> + */
> +
> +#include <xen/bitops.h>
> +#include <xen/sched.h>
> +#include <xen/sizes.h>
> +#include <asm/new_vgic.h>
> +
> +#include "vgic.h"
> +#include "vgic-mmio.h"
> +
> +static const struct vgic_register_region vgic_v2_dist_registers[] = {
> +    REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
> +        vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICACTIVER,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +    REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 2,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
> +        VGIC_ACCESS_32bit),
> +    REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +    REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
> +        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> +        VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
> +};
> +
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)
> +{
> +    dev->regions = vgic_v2_dist_registers;
> +    dev->nr_regions = ARRAY_SIZE(vgic_v2_dist_registers);
> +
> +    return SZ_4K;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> index 866023a84d..a03e8d88b9 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.c
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -170,6 +170,31 @@ struct mmio_handler_ops vgic_io_ops = {
>      .write = dispatch_mmio_write,
>  };
>  
> +int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
> +                             enum vgic_type type)
> +{
> +    struct vgic_io_device *io_device = &d->arch.vgic.dist_iodev;
> +    unsigned int len;
> +
> +    switch ( type )
> +    {
> +    case VGIC_V2:
> +        len = vgic_v2_init_dist_iodev(io_device);
> +        break;
> +    default:
> +        BUG();
> +    }
> +
> +    io_device->base_fn = dist_base_fn;
> +    io_device->iodev_type = IODEV_DIST;
> +    io_device->redist_vcpu = NULL;
> +
> +    register_mmio_handler(d, &vgic_io_ops, gfn_to_gaddr(dist_base_fn), len,
> +                          io_device);
> +
> +    return 0;
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> index bf062a27ca..c280668694 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.h
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -86,4 +86,6 @@ unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
>  void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>                          unsigned int len, unsigned long val);
>  
> +unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
> +
>  #endif
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index 41cc0c5b54..7f221fd195 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -49,6 +49,8 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>  void vgic_v2_fold_lr_state(struct vcpu *vcpu);
>  void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct vcpu *vcpu);
> +int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
> +                             enum vgic_type);
>  
>  #endif
>  
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers
  2018-03-21 16:32 ` [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers Andre Przywara
  2018-03-22  7:33   ` Julien Grall
@ 2018-03-27 20:38   ` Stefano Stabellini
  2018-03-28 10:36     ` Andre Przywara
  1 sibling, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 20:38 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Those three registers are v2 emulation specific, so their implementation
> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> as their implementation is pretty simple.
> We choose to piggy-back on the existing KVM identification registers,
> but use a different variant (major revision).

CC'ing Marc.

Reusing the KVM product ID could cause issues, for instance we could
clash with KVM if Linux changes the Major number. If we were to actually
reuse KVM's PRODUCT_ID we would need a better coordination in place.

I suggest to either introduce a Xen specific PRODUCT_ID, or simply reuse
the hardware value like the old vgic does for now. We can fix this
later.

In fact, I would be happy to swith to KVM's product id after appropriate
discussions with the KVM community. At the very least, it would need to
be written down somewhere under docs/ and/or Documentation.

Marc, what do you think?


> When the guest enables the distributor, we kick all VCPUs to get
> potentially pending interrupts serviced.
> 
> This is based on Linux commit 2b0cda878965, written by Marc Zyngier.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> Changelog v2 ... v3:
> - fix misleading comment about PRODUCT_ID letter
> - clarify on meaning of VARIANT_ID_XEN
> 
> Changelog v1 ... v2:
> use new IIDR values (KVM product ID, Xen revision)
> - add comment on handling GICD enablement
> - use new vcpu_kick() function
> 
>  xen/arch/arm/vgic/vgic-mmio-v2.c | 63 +++++++++++++++++++++++++++++++++++++++-
>  xen/arch/arm/vgic/vgic.c         | 15 ++++++++++
>  xen/arch/arm/vgic/vgic.h         |  9 ++++++
>  3 files changed, 86 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index 6f10cf16ca..43c1ab5906 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -20,9 +20,70 @@
>  #include "vgic.h"
>  #include "vgic-mmio.h"
>  
> +static unsigned long vgic_mmio_read_v2_misc(struct vcpu *vcpu,
> +                                            paddr_t addr, unsigned int len)
> +{
> +    uint32_t value;
> +
> +    switch ( addr & 0x0c )      /* filter for the 4 registers handled here */
> +    {
> +    case GICD_CTLR:
> +        value = vcpu->domain->arch.vgic.enabled ? GICD_CTL_ENABLE : 0;
> +        break;
> +    case GICD_TYPER:
> +        value = vcpu->domain->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
> +        value = (value >> 5) - 1;
> +        value |= (vcpu->domain->max_vcpus - 1) << 5;

NIT: You can reuse GICD_TYPE_CPUS_SHIFT


> +        break;
> +    case GICD_IIDR:
> +        value = (PRODUCT_ID_KVM << 24) |
> +                (VARIANT_ID_XEN << 16) |
> +                (IMPLEMENTER_ARM << 0);
> +        break;
> +    default:
> +        return 0;
> +    }
> +
> +    return value;
> +}
> +
> +static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
> +                                    paddr_t addr, unsigned int len,
> +                                    unsigned long val)
> +{
> +    struct vgic_dist *dist = &vcpu->domain->arch.vgic;
> +    bool enabled;
> +
> +    switch ( addr & 0x0c )      /* filter for the 4 registers handled here */
> +    {
> +    case GICD_CTLR:
> +        domain_lock(vcpu->domain);
> +
> +        /*
> +         * Store the new enabled state in our distributor structure.
> +         * Work out whether it was disabled before and now got enabled,
> +         * so that we signal all VCPUs to check for interrupts to be injected.
> +         */
> +        enabled = dist->enabled;
> +        dist->enabled = val & GICD_CTL_ENABLE;
> +        enabled = !enabled && dist->enabled;
> +
> +        domain_unlock(vcpu->domain);
> +
> +        if ( enabled )
> +            vgic_kick_vcpus(vcpu->domain);
> +
> +        break;
> +    case GICD_TYPER:
> +    case GICD_IIDR:
> +        /* read-only, writes ignored */
> +        return;
> +    }
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>      REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
> +        vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
>          vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 925cda4580..37b425a16c 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -684,6 +684,21 @@ int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>      return ret;
>  }
>  
> +void vgic_kick_vcpus(struct domain *d)
> +{
> +    struct vcpu *vcpu;
> +
> +    /*
> +     * We've injected an interrupt, time to find out who deserves
> +     * a good kick...
> +     */
> +    for_each_vcpu( d, vcpu )
> +    {
> +        if ( vgic_vcpu_pending_irq(vcpu) )
> +            vcpu_kick(vcpu);
> +    }
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index 7f221fd195..aed7e4179a 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -17,6 +17,14 @@
>  #ifndef __XEN_ARM_VGIC_VGIC_H__
>  #define __XEN_ARM_VGIC_VGIC_H__
>  
> +/*
> + * We piggy-back on the already used KVM product ID,  but use a different
> + * variant (major revision) for Xen.
> + */
> +#define PRODUCT_ID_KVM          0x4b        /* ASCII code K */
> +#define VARIANT_ID_XEN          0x01
> +#define IMPLEMENTER_ARM         0x43b
> +
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
>  static inline bool irq_is_pending(struct vgic_irq *irq)
> @@ -37,6 +45,7 @@ struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
>  void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
>  void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
>                             unsigned long flags);
> +void vgic_kick_vcpus(struct domain *d);
>  
>  static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>  {

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers
  2018-03-21 16:32 ` [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers Andre Przywara
@ 2018-03-27 21:06   ` Stefano Stabellini
  2018-03-28  9:09     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 21:06 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> As the enable register handlers are shared between the v2 and v3
> emulation, their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> This introduces a vgic_sync_hardware_irq() function, which updates the
> physical side of a hardware mapped virtual IRQ.
> Because the existing locking order between vgic_irq->irq_lock and
> irq_desc->lock dictates so, we drop the irq_lock and retake them in the
> proper order.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
> Changelog v2 ... v3:
> - fix indentation
> - fix wording in comment
> - add Reviewed-by:
> 
> Changelog v1 ... v2:
> - ASSERT on h/w IRQ and vIRQ staying in sync
> 
>  xen/arch/arm/vgic/vgic-mmio-v2.c |   4 +-
>  xen/arch/arm/vgic/vgic-mmio.c    | 117 +++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.h    |  11 ++++
>  xen/arch/arm/vgic/vgic.c         |  40 +++++++++++++
>  xen/arch/arm/vgic/vgic.h         |   3 +
>  5 files changed, 173 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index 43c1ab5906..7efd1c4eb4 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -89,10 +89,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
>          vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> index a03e8d88b9..f219b7c509 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.c
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -39,6 +39,123 @@ void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>      /* Ignore */
>  }
>  
> +/*
> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> + * of the enabled bit, so there is only one function for both here.
> + */
> +unsigned long vgic_mmio_read_enable(struct vcpu *vcpu,
> +                                    paddr_t addr, unsigned int len)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    uint32_t value = 0;
> +    unsigned int i;
> +
> +    /* Loop over all IRQs affected by this read */
> +    for ( i = 0; i < len * 8; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        if ( irq->enabled )
> +            value |= (1U << i);

Don't we need to take the irq->irq_lock before reading irq->enabled?


> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +
> +    return value;
> +}
> +
> +void vgic_mmio_write_senable(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    unsigned int i;
> +
> +    for_each_set_bit( i, &val, len * 8 )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +        unsigned long flags;
> +        irq_desc_t *desc;
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        if ( irq->enabled )            /* skip already enabled IRQs */
> +        {
> +            spin_unlock_irqrestore(&irq->irq_lock, flags);
> +            vgic_put_irq(vcpu->domain, irq);
> +            continue;
> +        }
> +
> +        irq->enabled = true;
> +        if ( irq->hw )
> +        {
> +            /*
> +             * The irq cannot be a PPI, we only support delivery
> +             * of SPIs to guests.
> +             */
> +            ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
> +
> +            desc = irq_to_desc(irq->hwintid);
> +        }
> +        else
> +            desc = NULL;
> +
> +        vgic_queue_irq_unlock(vcpu->domain, irq, flags);
> +
> +        if ( desc )
> +            vgic_sync_hardware_irq(vcpu->domain, desc, irq);
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
> +void vgic_mmio_write_cenable(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    unsigned int i;
> +
> +    for_each_set_bit( i, &val, len * 8 )
> +    {
> +        struct vgic_irq *irq;
> +        unsigned long flags;
> +        irq_desc_t *desc;
> +
> +        irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        if ( !irq->enabled )            /* skip already disabled IRQs */
> +        {
> +            spin_unlock_irqrestore(&irq->irq_lock, flags);
> +            vgic_put_irq(vcpu->domain, irq);
> +            continue;
> +        }
> +
> +        irq->enabled = false;
> +
> +        if ( irq->hw )
> +        {
> +            /*
> +             * The irq cannot be a PPI, we only support delivery
> +             * of SPIs to guests.
> +             */
> +            ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
> +
> +            desc = irq_to_desc(irq->hwintid);
> +        }
> +        else
> +            desc = NULL;
> +
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +        if ( desc )
> +            vgic_sync_hardware_irq(vcpu->domain, desc, irq);
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
>  static int match_region(const void *key, const void *elt)
>  {
>      const unsigned int offset = (unsigned long)key;
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> index c280668694..a2cebd77f4 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.h
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -86,6 +86,17 @@ unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
>  void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>                          unsigned int len, unsigned long val);
>  
> +unsigned long vgic_mmio_read_enable(struct vcpu *vcpu,
> +                                    paddr_t addr, unsigned int len);
> +
> +void vgic_mmio_write_senable(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val);
> +
> +void vgic_mmio_write_cenable(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 37b425a16c..90041eb071 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -699,6 +699,46 @@ void vgic_kick_vcpus(struct domain *d)
>      }
>  }
>  
> +static unsigned int translate_irq_type(bool is_level)
> +{
> +    return is_level ? IRQ_TYPE_LEVEL_HIGH : IRQ_TYPE_EDGE_RISING;
> +}
> +
> +void vgic_sync_hardware_irq(struct domain *d,
> +                            irq_desc_t *desc, struct vgic_irq *irq)
> +{
> +    unsigned long flags;
> +
> +    spin_lock_irqsave(&desc->lock, flags);
> +    spin_lock(&irq->irq_lock);
> +
> +    /*
> +     * We forbid tinkering with the hardware IRQ association during
> +     * a domain's lifetime.
> +     */
> +    ASSERT(irq->hw && desc->irq == irq->hwintid);
> +
> +    if ( irq->enabled )
> +    {
> +        /*
> +         * We might end up from various callers, so check that the
> +         * interrrupt is disabled before trying to change the config.
> +         */
> +        if ( irq_type_set_by_domain(d) &&
> +             test_bit(_IRQ_DISABLED, &desc->status) )
> +            gic_set_irq_type(desc, translate_irq_type(irq->config));
> +
> +        if ( irq->target_vcpu )
> +            irq_set_affinity(desc, cpumask_of(irq->target_vcpu->processor));
> +        desc->handler->enable(desc);
> +    }
> +    else
> +        desc->handler->disable(desc);
> +
> +    spin_unlock(&irq->irq_lock);
> +    spin_unlock_irqrestore(&desc->lock, flags);
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index aed7e4179a..071e061066 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -55,6 +55,9 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>      atomic_inc(&irq->refcount);
>  }
>  
> +void vgic_sync_hardware_irq(struct domain *d,
> +                            irq_desc_t *desc, struct vgic_irq *irq);
> +
>  void vgic_v2_fold_lr_state(struct vcpu *vcpu);
>  void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct vcpu *vcpu);
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 20/39] ARM: new VGIC: Add PENDING registers handlers
  2018-03-21 16:32 ` [PATCH v3 20/39] ARM: new VGIC: Add PENDING " Andre Przywara
@ 2018-03-27 21:14   ` Stefano Stabellini
  2018-03-28 14:10     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 21:14 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The pending register handlers are shared between the v2 and v3
> emulation, so their implementation goes into vgic-mmio.c, to be easily
> referenced from the v3 emulation as well later.
> For level triggered interrupts the real line level is unaffected by
> this write, so we keep this state separate and combine it with the
> device's level to get the actual pending state.
> Hardware mapped IRQs need some special handling, as their hardware state
> has to be coordinated with the virtual pending bit to avoid hanging
> or masked interrupts.
> 
> This is based on Linux commit 96b298000db4, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic-mmio-v2.c |   4 +-
>  xen/arch/arm/vgic/vgic-mmio.c    | 125 +++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.h    |  11 ++++
>  3 files changed, 138 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index 7efd1c4eb4..a48c554040 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -95,10 +95,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
>          vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> index f219b7c509..53b8978c02 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.c
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -156,6 +156,131 @@ void vgic_mmio_write_cenable(struct vcpu *vcpu,
>      }
>  }
>  
> +unsigned long vgic_mmio_read_pending(struct vcpu *vcpu,
> +                                     paddr_t addr, unsigned int len)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    uint32_t value = 0;
> +    unsigned int i;
> +
> +    /* Loop over all IRQs affected by this read */
> +    for ( i = 0; i < len * 8; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        if ( irq_is_pending(irq) )
> +            value |= (1U << i);

Same question: shouldn't we take the irq->irq_lock?


> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +
> +    return value;
> +}
> +
> +void vgic_mmio_write_spending(struct vcpu *vcpu,
> +                              paddr_t addr, unsigned int len,
> +                              unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    unsigned int i;
> +    unsigned long flags;
> +    irq_desc_t *desc;
> +
> +    for_each_set_bit( i, &val, len * 8 )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +        irq->pending_latch = true;
> +
> +        /* To observe the locking order, just take the irq_desc pointer here. */
> +        if ( irq->hw )
> +            desc = irq_to_desc(irq->hwintid);
> +        else
> +            desc = NULL;
> +
> +        vgic_queue_irq_unlock(vcpu->domain, irq, flags);
> +
> +        /*
> +         * When the VM sets the pending state for a HW interrupt on the virtual
> +         * distributor we set the active state on the physical distributor,
> +         * because the virtual interrupt can become active and then the guest
> +         * can deactivate it.
> +         */
> +        if ( desc )
> +        {
> +            spin_lock_irqsave(&desc->lock, flags);
> +            spin_lock(&irq->irq_lock);
> +
> +            /* This h/w IRQ should still be assigned to the virtual IRQ. */
> +            ASSERT(irq->hw && desc->irq == irq->hwintid);
> +
> +            gic_set_active_state(desc, true);
> +
> +            spin_unlock(&irq->irq_lock);
> +            spin_unlock_irqrestore(&desc->lock, flags);
> +        }
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
> +void vgic_mmio_write_cpending(struct vcpu *vcpu,
> +                              paddr_t addr, unsigned int len,
> +                              unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    unsigned int i;
> +    unsigned long flags;
> +    irq_desc_t *desc;
> +
> +    for_each_set_bit( i, &val, len * 8 )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +        irq->pending_latch = false;
> +
> +        /* To observe the locking order, just take the irq_desc pointer here. */
> +        if ( irq->hw )
> +            desc = irq_to_desc(irq->hwintid);
> +        else
> +            desc = NULL;
> +
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +        /*
> +         * We don't want the guest to effectively mask the physical
> +         * interrupt by doing a write to SPENDR followed by a write to
> +         * CPENDR for HW interrupts, so we clear the active state on
> +         * the physical side if the virtual interrupt is not active.
> +         * This may lead to taking an additional interrupt on the
> +         * host, but that should not be a problem as the worst that
> +         * can happen is an additional vgic injection.  We also clear
> +         * the pending state to maintain proper semantics for edge HW
> +         * interrupts.
> +         */
> +        if ( desc )
> +        {
> +            spin_lock_irqsave(&desc->lock, flags);
> +            spin_lock(&irq->irq_lock);
> +
> +            /* This h/w IRQ should still be assigned to the virtual IRQ. */
> +            ASSERT(irq->hw && desc->irq == irq->hwintid);
> +
> +            gic_set_pending_state(desc, false);

Should we check irq_is_pending before calling gic_set_pending_state? I
am asking because I think it is possible to race against another
concurrent change that could come in after releasing irq_lock and before
taking desc->lock and irq->irq_lock again. If we check what's the latest
about the pending state we should be safe against the race, similarly to
what you did in the previous patch in vgic_sync_hardware_irq.


> +            if (!irq->active)
> +                gic_set_active_state(desc, false);
> +
> +            spin_unlock(&irq->irq_lock);
> +            spin_unlock_irqrestore(&desc->lock, flags);
> +        }
> +
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
>  static int match_region(const void *key, const void *elt)
>  {
>      const unsigned int offset = (unsigned long)key;
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> index a2cebd77f4..5c927f28b0 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.h
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -97,6 +97,17 @@ void vgic_mmio_write_cenable(struct vcpu *vcpu,
>                               paddr_t addr, unsigned int len,
>                               unsigned long val);
>  
> +unsigned long vgic_mmio_read_pending(struct vcpu *vcpu,
> +                                     paddr_t addr, unsigned int len);
> +
> +void vgic_mmio_write_spending(struct vcpu *vcpu,
> +                              paddr_t addr, unsigned int len,
> +                              unsigned long val);
> +
> +void vgic_mmio_write_cpending(struct vcpu *vcpu,
> +                              paddr_t addr, unsigned int len,
> +                              unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 21/39] ARM: new VGIC: Add ACTIVE registers handlers
  2018-03-21 16:32 ` [PATCH v3 21/39] ARM: new VGIC: Add ACTIVE " Andre Przywara
@ 2018-03-27 21:21   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 21:21 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The active register handlers are shared between the v2 and v3 emulation,
> so their implementation goes into vgic-mmio.c, to be easily referenced
> from the v3 emulation as well later.
> Since activation/deactivation of an interrupt may happen entirely in the
> guest without it ever exiting, we need some extra logic to properly track
> the active state.
> For clearing the active state, we would basically have to halt the guest
> to make sure this is properly propagated into the respective VCPUs.
> This is not yet implemented in Xen.
> Fortunately this feature is mostly used to reset a just in initialised
> GIC, so chances are we are tasked to clear bits that are already zero.
> Add a simple check to avoid pointless warnings in this case.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic-mmio-v2.c |  4 +-
>  xen/arch/arm/vgic/vgic-mmio.c    | 91 ++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.h    | 11 +++++
>  3 files changed, 104 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index a48c554040..724681e0f8 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -101,10 +101,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        vgic_mmio_read_active, vgic_mmio_write_sactive, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICACTIVER,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> +        vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
>          vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> index 53b8978c02..b79e431f50 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.c
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -281,6 +281,97 @@ void vgic_mmio_write_cpending(struct vcpu *vcpu,
>      }
>  }
>  
> +/*
> + * The actual active bit for a virtual IRQ is held in the LR. Our shadow
> + * copy in struct vgic_irq is only synced when needed and may not be
> + * up-to-date all of the time.
> + * Returning the actual active state is quite costly (stopping all
> + * VCPUs processing any affected vIRQs), so we use a simple implementation
> + * to get the best possible answer.
> + */
> +unsigned long vgic_mmio_read_active(struct vcpu *vcpu,
> +                                    paddr_t addr, unsigned int len)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    uint32_t value = 0;
> +    unsigned int i;
> +
> +    /* Loop over all IRQs affected by this read */
> +    for ( i = 0; i < len * 8; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        if ( irq->active )
> +            value |= (1U << i);

Need for lock? I guess one answer will be good for all these patches :-)

Aside from this, everything else looks good.


> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +
> +    return value;
> +}
> +
> +/*
> + * We don't actually support clearing the active state of an IRQ (yet).
> + * However there is a chance that most guests use this for initialization.
> + * We check whether this MMIO access would actually affect any active IRQ,
> + * and only print our warning in this case. So clearing already non-active
> + * IRQs would not be moaned about in the logs.
> + */
> +void vgic_mmio_write_cactive(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    unsigned int i;
> +
> +    for_each_set_bit( i, &val, len * 8 )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        /*
> +         * If we know that the IRQ is active or we can't be sure about
> +         * it (because it is currently in a CPU), log the not properly
> +         * emulated MMIO access.
> +         */
> +        if ( irq->active || irq->vcpu )
> +            printk(XENLOG_G_ERR
> +                   "%pv: vGICD: IRQ%u: clearing active state not supported\n",
> +                   vcpu, irq->intid);
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
> +/*
> + * We don't actually support setting the active state of an IRQ (yet).
> + * We check whether this MMIO access would actually affect any non-active IRQ,
> + * and only print our warning in this case.
> + */
> +void vgic_mmio_write_sactive(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> +    unsigned int i;
> +
> +    for_each_set_bit( i, &val, len * 8 )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        /*
> +         * If we know that the IRQ is not active or we can't be sure about
> +         * it (because it is currently in a CPU), log the not properly
> +         * emulated MMIO access.
> +         */
> +        if ( !irq->active || irq->vcpu )
> +            printk(XENLOG_G_ERR
> +                   "%pv: vGICD: IRQ%u: setting active state not supported\n",
> +                   vcpu, irq->intid);
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
>  static int match_region(const void *key, const void *elt)
>  {
>      const unsigned int offset = (unsigned long)key;
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> index 5c927f28b0..832e2eb3d8 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.h
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -108,6 +108,17 @@ void vgic_mmio_write_cpending(struct vcpu *vcpu,
>                                paddr_t addr, unsigned int len,
>                                unsigned long val);
>  
> +unsigned long vgic_mmio_read_active(struct vcpu *vcpu,
> +                                    paddr_t addr, unsigned int len);
> +
> +void vgic_mmio_write_cactive(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val);
> +
> +void vgic_mmio_write_sactive(struct vcpu *vcpu,
> +                             paddr_t addr, unsigned int len,
> +                             unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 22/39] ARM: new VGIC: Add PRIORITY registers handlers
  2018-03-21 16:32 ` [PATCH v3 22/39] ARM: new VGIC: Add PRIORITY " Andre Przywara
@ 2018-03-27 21:24   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 21:24 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The priority register handlers are shared between the v2 and v3 emulation,
> so their implementation goes into vgic-mmio.c, to be easily referenced
> from the v3 emulation as well later.
> 
> This is based on Linux commit 055658bf48fc, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic-mmio-v2.c |  2 +-
>  xen/arch/arm/vgic/vgic-mmio.c    | 47 ++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.h    |  7 ++++++
>  xen/arch/arm/vgic/vgic.h         |  2 ++
>  4 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index 724681e0f8..d2d6a07e1b 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -107,7 +107,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_active, vgic_mmio_write_cactive, 1,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IPRIORITYR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> +        vgic_mmio_read_priority, vgic_mmio_write_priority, 8,
>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ITARGETSR,
>          vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> index b79e431f50..14b69d80d4 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.c
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -372,6 +372,53 @@ void vgic_mmio_write_sactive(struct vcpu *vcpu,
>      }
>  }
>  
> +unsigned long vgic_mmio_read_priority(struct vcpu *vcpu,
> +                                      paddr_t addr, unsigned int len)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> +    unsigned int i;
> +    uint32_t val = 0;
> +
> +    for ( i = 0; i < len; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        val |= (uint32_t)irq->priority << (i * 8);

same question


> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +
> +    return val;
> +}
> +
> +/*
> + * We currently don't handle changing the priority of an interrupt that
> + * is already pending on a VCPU. If there is a need for this, we would
> + * need to make this VCPU exit and re-evaluate the priorities, potentially
> + * leading to this interrupt getting presented now to the guest (if it has
> + * been masked by the priority mask before).

Sounds good to me. Aside from the locking question, the patch is fine.


> + */
> +void vgic_mmio_write_priority(struct vcpu *vcpu,
> +                              paddr_t addr, unsigned int len,
> +                              unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> +    unsigned int i;
> +    unsigned long flags;
> +
> +    for ( i = 0; i < len; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +        /* Narrow the priority range to what we actually support */
> +        irq->priority = (val >> (i * 8)) & GENMASK(7, 8 - VGIC_PRI_BITS);
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
>  static int match_region(const void *key, const void *elt)
>  {
>      const unsigned int offset = (unsigned long)key;
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> index 832e2eb3d8..b2d572d562 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.h
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -119,6 +119,13 @@ void vgic_mmio_write_sactive(struct vcpu *vcpu,
>                               paddr_t addr, unsigned int len,
>                               unsigned long val);
>  
> +unsigned long vgic_mmio_read_priority(struct vcpu *vcpu,
> +                      paddr_t addr, unsigned int len);
> +
> +void vgic_mmio_write_priority(struct vcpu *vcpu,
> +                  paddr_t addr, unsigned int len,
> +                  unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index 071e061066..c7eeaf7a38 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -25,6 +25,8 @@
>  #define VARIANT_ID_XEN          0x01
>  #define IMPLEMENTER_ARM         0x43b
>  
> +#define VGIC_PRI_BITS       5
> +
>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>  
>  static inline bool irq_is_pending(struct vgic_irq *irq)
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 23/39] ARM: new VGIC: Add CONFIG registers handlers
  2018-03-21 16:32 ` [PATCH v3 23/39] ARM: new VGIC: Add CONFIG " Andre Przywara
@ 2018-03-27 21:26   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 21:26 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The config register handlers are shared between the v2 and v3 emulation,
> so their implementation goes into vgic-mmio.c, to be easily referenced
> from the v3 emulation as well later.
> 
> This is based on Linux commit 79717e4ac09c, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic-mmio-v2.c |  2 +-
>  xen/arch/arm/vgic/vgic-mmio.c    | 54 ++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic-mmio.h    |  7 ++++++
>  3 files changed, 62 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index d2d6a07e1b..a28d0e459b 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -113,7 +113,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_raz, vgic_mmio_write_wi, 8,
>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICFGR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 2,
> +        vgic_mmio_read_config, vgic_mmio_write_config, 2,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
>          vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> index 14b69d80d4..5bcb02e8c6 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.c
> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> @@ -419,6 +419,60 @@ void vgic_mmio_write_priority(struct vcpu *vcpu,
>      }
>  }
>  
> +unsigned long vgic_mmio_read_config(struct vcpu *vcpu,
> +                                    paddr_t addr, unsigned int len)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 2);
> +    uint32_t value = 0;
> +    int i;
> +
> +    for ( i = 0; i < len * 4; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        if ( irq->config == VGIC_CONFIG_EDGE )
> +            value |= (2U << (i * 2));

same question

Everything else looks good

> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +
> +    return value;
> +}
> +
> +void vgic_mmio_write_config(struct vcpu *vcpu,
> +                            paddr_t addr, unsigned int len,
> +                            unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 2);
> +    int i;
> +    unsigned long flags;
> +
> +    for ( i = 0; i < len * 4; i++ )
> +    {
> +        struct vgic_irq *irq;
> +
> +        /*
> +         * The configuration cannot be changed for SGIs in general,
> +         * for PPIs this is IMPLEMENTATION DEFINED. The arch timer
> +         * code relies on PPIs being level triggered, so we also
> +         * make them read-only here.
> +         */
> +        if ( intid + i < VGIC_NR_PRIVATE_IRQS )
> +            continue;
> +
> +        irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        if ( test_bit(i * 2 + 1, &val) )
> +            irq->config = VGIC_CONFIG_EDGE;
> +        else
> +            irq->config = VGIC_CONFIG_LEVEL;
> +
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
>  static int match_region(const void *key, const void *elt)
>  {
>      const unsigned int offset = (unsigned long)key;
> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
> index b2d572d562..3566cf237c 100644
> --- a/xen/arch/arm/vgic/vgic-mmio.h
> +++ b/xen/arch/arm/vgic/vgic-mmio.h
> @@ -126,6 +126,13 @@ void vgic_mmio_write_priority(struct vcpu *vcpu,
>                    paddr_t addr, unsigned int len,
>                    unsigned long val);
>  
> +unsigned long vgic_mmio_read_config(struct vcpu *vcpu,
> +                    paddr_t addr, unsigned int len);
> +
> +void vgic_mmio_write_config(struct vcpu *vcpu,
> +                paddr_t addr, unsigned int len,
> +                unsigned long val);
> +
>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>  
>  #endif
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework
  2018-03-27 19:20         ` Stefano Stabellini
@ 2018-03-27 22:13           ` André Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: André Przywara @ 2018-03-27 22:13 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

On 27/03/18 20:20, Stefano Stabellini wrote:
> On Tue, 27 Mar 2018, Stefano Stabellini wrote:
>> On Tue, 27 Mar 2018, Andre Przywara wrote:
>>> Hi,
>>>
>>> On 26/03/18 22:30, Stefano Stabellini wrote:
>>>> On Wed, 21 Mar 2018, Andre Przywara wrote:
>>>>> Implement the framework for syncing IRQs between our emulation and the
>>>>> list registers, which represent the guest's view of IRQs.
>>>>> This is done in vgic_sync_from_lrs() and vgic_sync_to_lrs(), which
>>>>> get called on guest entry and exit, respectively.
>>>>> The code talking to the actual GICv2/v3 hardware is added in the
>>>>> following patches.
>>>>>
>>>>> This is based on Linux commit 0919e84c0fc1, written by Marc Zyngier.
>>>>>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>>>>
>>>> Just one question below, but the code looks nice
>>>>
>>>>
>>>>> ---
>>>>> Changelog v2 ... v3:
>>>>> - replace "true" instead of "1" for the boolean parameter
>>>>>
>>>>> Changelog v1 ... v2:
>>>>> - make functions void
>>>>> - do underflow setting directly (no v2/v3 indirection)
>>>>> - fix multiple SGIs injections (as the late Linux bugfix)
>>>>>
>>>>>  xen/arch/arm/vgic/vgic.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++
>>>>>  xen/arch/arm/vgic/vgic.h |   2 +
>>>>>  2 files changed, 234 insertions(+)
>>>>>
>>>>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>>>>> index ee0de8d2e0..52e1669888 100644
>>>>> --- a/xen/arch/arm/vgic/vgic.c
>>>>> +++ b/xen/arch/arm/vgic/vgic.c
>>>>> @@ -409,6 +409,238 @@ void vgic_inject_irq(struct domain *d, struct vcpu *vcpu, unsigned int intid,
>>>
>>> ....
>>>
>>>>> +/* Requires the ap_list_lock to be held. */
>>>>> +static int compute_ap_list_depth(struct vcpu *vcpu)
>>>>> +{
>>>>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
>>>>> +    struct vgic_irq *irq;
>>>>> +    int count = 0;
>>>>> +
>>>>> +    ASSERT(spin_is_locked(&vgic_cpu->ap_list_lock));
>>>>> +
>>>>> +    list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list)
>>>>> +    {
>>>>> +        spin_lock(&irq->irq_lock);
>>>>> +        /* GICv2 SGIs can count for more than one... */
>>>>> +        if ( vgic_irq_is_sgi(irq->intid) && irq->source )
>>>>> +            count += hweight8(irq->source);
>>>>
>>>> Why is this done?
>>>
>>> GICv2 SGIs always have a source CPU ID connected to them. So if two CPUs
>>> signal another CPU at the same time, there are *two* distinct SGIs, with
>>> two different source IDs. This is an architectural feature of GICv2, so
>>> we have to properly emulate this.
>>> Despite them being edge triggered IRQs, we cannot coalesce them in this
>>> case.
>>
>> I went through the whole lifecycle of SGIs with the new vgic and it is
>> quite different from before, but it makes sense to me now.
>>
>> Acked-by: Stefano Stabellini <sstabellini@kernel.org>
> 
> Actually, I take it back, one more question :-)
> 
> I understand that every bit set in irq->source corresponds to a
> different interrupt that needs to be injected into the guest. They are
> distinct interrupts.
> 
> However, compute_ap_list_depth is called to figure out whether the
> entries in ap_list overflow the LR registers, and it is never the case
> that we write to more than one LR register for a given SGI, even if
> irq->source has multiple bit sets, right?

Yes, that was actually a recent change in KVM:
https://lists.cs.columbia.edu/pipermail/kvmarm/2018-March/030226.html

So I basically took this patch right into the series.

Now there are more subtleties about priorities (see the follow-ups on
this thread), which actually led to a different patch being merged:
https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git/commit/?id=16ca6a607
(what I only learned today).
So this is a bit more sophisticated, and needs some porting because of
the new "empty LR" interrupt. I would rather do this on top.

> In a concrete example, if we have 3 LR registers and 3 interrupts in
> ap_list, one of them is an SGI with multiple irq->source bits, there is
> still no need to sort the ap_list, correct?
> 
> I think we should remove the special if statement for sgis in
> compute_ap_list_depth.

Yes, I believe this is a good intermediate measure, until we get the
proper solution.
Let me test this tomorrow, then I can push a reworked version of this patch.

Cheers,
Andre.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler
  2018-03-21 16:32 ` [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler Andre Przywara
  2018-03-22  7:54   ` Julien Grall
@ 2018-03-27 22:23   ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:23 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Triggering an IPI via this register is v2 specific, so the
> implementation lives entirely in vgic-mmio-v2.c.
> 
> This is based on Linux commit 55cc01fb9004, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
> Changelog v2 ... v3:
> - fix target mask calculation
> 
> Changelog v1 ... v2:
> - remove stray rebase artefact
> 
>  xen/arch/arm/vgic/vgic-mmio-v2.c | 45 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 44 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index b333de9ed7..9ef80608c1 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -81,6 +81,49 @@ static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
>      }
>  }
>  
> +static void vgic_mmio_write_sgir(struct vcpu *source_vcpu,
> +                                 paddr_t addr, unsigned int len,
> +                                 unsigned long val)
> +{
> +    struct domain *d = source_vcpu->domain;
> +    unsigned int nr_vcpus = d->max_vcpus;
> +    unsigned int intid = val & GICD_SGI_INTID_MASK;
> +    unsigned long targets = (val & GICD_SGI_TARGET_MASK) >>
> +                            GICD_SGI_TARGET_SHIFT;
> +    unsigned int vcpu_id;
> +
> +    switch ( val & GICD_SGI_TARGET_LIST_MASK )
> +    {
> +    case GICD_SGI_TARGET_LIST:                    /* as specified by targets */
> +        targets &= GENMASK(nr_vcpus - 1, 0);      /* limit to existing VCPUs */
> +        break;
> +    case GICD_SGI_TARGET_OTHERS:
> +        targets = GENMASK(nr_vcpus - 1, 0);       /* all, ...   */
> +        targets &= ~(1U << source_vcpu->vcpu_id); /*   but self */
> +        break;
> +    case GICD_SGI_TARGET_SELF:                    /* this very vCPU only */
> +        targets = (1U << source_vcpu->vcpu_id);
> +        break;
> +    case 0x3:                                     /* reserved */
> +        return;
> +    }
> +
> +    for_each_set_bit( vcpu_id, &targets, 8 )
> +    {
> +        struct vcpu *vcpu = d->vcpu[vcpu_id];
> +        struct vgic_irq *irq = vgic_get_irq(d, vcpu, intid);
> +        unsigned long flags;
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        irq->pending_latch = true;
> +        irq->source |= 1U << source_vcpu->vcpu_id;
> +
> +        vgic_queue_irq_unlock(d, irq, flags);
> +        vgic_put_irq(d, irq);
> +    }
> +}
> +
>  static unsigned long vgic_mmio_read_target(struct vcpu *vcpu,
>                                             paddr_t addr, unsigned int len)
>  {
> @@ -173,7 +216,7 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_config, vgic_mmio_write_config, 2,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_LENGTH(GICD_SGIR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 4,
> +        vgic_mmio_read_raz, vgic_mmio_write_sgir, 4,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
>          vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers
  2018-03-21 16:32 ` [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers Andre Przywara
@ 2018-03-27 22:27   ` Stefano Stabellini
  2018-03-28 10:37     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:27 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> As this register is v2 specific, its implementation lives entirely
> in vgic-mmio-v2.c.
> This register allows setting the source mask of an IPI.
> 
> This is based on Linux commit ed40213ef9b0, written by Andre Przywara.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic-mmio-v2.c | 81 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 79 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> index 9ef80608c1..32e0f6fc33 100644
> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> @@ -181,6 +181,83 @@ static void vgic_mmio_write_target(struct vcpu *vcpu,
>      }
>  }
>  
> +static unsigned long vgic_mmio_read_sgipend(struct vcpu *vcpu,
> +                                            paddr_t addr, unsigned int len)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> +    uint32_t val = 0;
> +    unsigned int i;
> +
> +    ASSERT(intid < VGIC_NR_SGIS);
> +
> +    for ( i = 0; i < len; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        val |= (uint32_t)irq->source << (i * 8);

lock?
one more comment


> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +
> +    return val;
> +}
> +
> +static void vgic_mmio_write_sgipendc(struct vcpu *vcpu,
> +                                     paddr_t addr, unsigned int len,
> +                                     unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> +    unsigned int i;
> +    unsigned long flags;
> +
> +    ASSERT(intid < VGIC_NR_SGIS);
> +
> +    for ( i = 0; i < len; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        irq->source &= ~((val >> (i * 8)) & 0xff);
> +        if ( !irq->source )
> +            irq->pending_latch = false;
> +
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
> +static void vgic_mmio_write_sgipends(struct vcpu *vcpu,
> +                                     paddr_t addr, unsigned int len,
> +                                     unsigned long val)
> +{
> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> +    unsigned int i;
> +    unsigned long flags;
> +
> +    ASSERT(intid < VGIC_NR_SGIS);
> +
> +    for ( i = 0; i < len; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        irq->source |= (val >> (i * 8)) & 0xff;
> +
> +        if ( irq->source )
> +        {
> +            irq->pending_latch = true;
> +            vgic_queue_irq_unlock(vcpu->domain, irq, flags);
> +        }
> +        else
> +        {
> +            spin_unlock_irqrestore(&irq->irq_lock, flags);
> +        }

NIT: it should be safe to call vgic_queue_irq_unlock regardless, right?


> +        vgic_put_irq(vcpu->domain, irq);
> +    }
> +}
> +
>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>      REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>          vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
> @@ -219,10 +296,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>          vgic_mmio_read_raz, vgic_mmio_write_sgir, 4,
>          VGIC_ACCESS_32bit),
>      REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> +        vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16,
>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>      REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
> +        vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16,
>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>  };
>  
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 27/39] ARM: new VGIC: Handle hardware mapped IRQs
  2018-03-21 16:32 ` [PATCH v3 27/39] ARM: new VGIC: Handle hardware mapped IRQs Andre Przywara
@ 2018-03-27 22:31   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:31 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The VGIC supports virtual IRQs to be connected to a hardware IRQ, so
> when a guest EOIs the virtual interrupt, it affects the state of that
> corresponding interrupt on the hardware side at the same time.
> Implement the interface that the Xen arch/core code expects to connect
> the virtual and the physical world.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/vgic/vgic.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 71 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 90041eb071..07866d7243 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -699,6 +699,77 @@ void vgic_kick_vcpus(struct domain *d)
>      }
>  }
>  
> +struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
> +                                      unsigned int virq)
> +{
> +    struct irq_desc *desc = NULL;
> +    struct vgic_irq *irq = vgic_get_irq(d, v, virq);
> +    unsigned long flags;
> +
> +    if ( !irq )
> +        return NULL;
> +
> +    spin_lock_irqsave(&irq->irq_lock, flags);
> +    if ( irq->hw )
> +    {
> +        ASSERT(irq->hwintid >= VGIC_NR_PRIVATE_IRQS);
> +        desc = irq_to_desc(irq->hwintid);
> +    }
> +    spin_unlock_irqrestore(&irq->irq_lock, flags);
> +
> +    vgic_put_irq(d, irq);
> +
> +    return desc;
> +}
> +
> +/*
> + * was:
> + *      int kvm_vgic_map_phys_irq(struct vcpu *vcpu, u32 virt_irq, u32 phys_irq)
> + *      int kvm_vgic_unmap_phys_irq(struct vcpu *vcpu, unsigned int virt_irq)
> + */
> +int vgic_connect_hw_irq(struct domain *d, struct vcpu *vcpu,
> +                        unsigned int virt_irq, struct irq_desc *desc,
> +                        bool connect)
> +{
> +    struct vgic_irq *irq = vgic_get_irq(d, vcpu, virt_irq);
> +    unsigned long flags;
> +    int ret = 0;
> +
> +    if ( !irq )
> +        return -EINVAL;
> +
> +    spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +    if ( connect )                      /* assign a mapped IRQ */
> +    {
> +        /* The VIRQ should not be already enabled by the guest */
> +        if ( !irq->hw && !irq->enabled )
> +        {
> +            irq->hw = true;
> +            irq->hwintid = desc->irq;
> +        }
> +        else
> +            ret = -EBUSY;
> +    }
> +    else                                /* remove a mapped IRQ */
> +    {
> +        if ( desc && irq->hwintid != desc->irq )
> +        {
> +            ret = -EINVAL;
> +        }
> +        else
> +        {
> +            irq->hw = false;
> +            irq->hwintid = 0;
> +        }
> +    }
> +
> +    spin_unlock_irqrestore(&irq->irq_lock, flags);
> +    vgic_put_irq(d, irq);
> +
> +    return ret;
> +}
> +
>  static unsigned int translate_irq_type(bool is_level)
>  {
>      return is_level ? IRQ_TYPE_LEVEL_HIGH : IRQ_TYPE_EDGE_RISING;
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 28/39] ARM: new VGIC: Add event channel IRQ handling
  2018-03-21 16:32 ` [PATCH v3 28/39] ARM: new VGIC: Add event channel IRQ handling Andre Przywara
@ 2018-03-27 22:33   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:33 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The Xen core/arch code relies on two abstracted functions to inject an
> event channel IRQ and to query its pending state.
> Implement those to query the state of the new VGIC implementation.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Acked-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/vgic/vgic.c | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 07866d7243..3d818a98ad 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -699,6 +699,29 @@ void vgic_kick_vcpus(struct domain *d)
>      }
>  }
>  
> +void arch_evtchn_inject(struct vcpu *v)
> +{
> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
> +}
> +
> +bool vgic_evtchn_irq_pending(struct vcpu *v)
> +{
> +    struct vgic_irq *irq;
> +    unsigned long flags;
> +    bool pending;
> +
> +    /* Does not work for LPIs. */
> +    ASSERT(!is_lpi(v->domain->arch.evtchn_irq));
> +
> +    irq = vgic_get_irq(v->domain, v, v->domain->arch.evtchn_irq);
> +    spin_lock_irqsave(&irq->irq_lock, flags);
> +    pending = irq_is_pending(irq);
> +    spin_unlock_irqrestore(&irq->irq_lock, flags);
> +    vgic_put_irq(v->domain, irq);
> +
> +    return pending;
> +}
> +
>  struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>                                        unsigned int virq)
>  {
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 29/39] ARM: new VGIC: Handle virtual IRQ allocation/reservation
  2018-03-21 16:32 ` [PATCH v3 29/39] ARM: new VGIC: Handle virtual IRQ allocation/reservation Andre Przywara
@ 2018-03-27 22:38   ` Stefano Stabellini
  2018-03-28  9:17     ` Andre Przywara
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:38 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> To find an unused virtual IRQ number Xen uses a scheme to track used
> virtual IRQs.
> Implement this interface in the new VGIC to make the Xen core/arch code
> happy.
> This is actually somewhat VGIC agnostic, so is mostly a copy of the code
> from the old VGIC. But it has to live in the VGIC files, so we can't
> easily reuse the existing implementation.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Acked-by: Julien Grall <julien.grall@arm.com>

These are exactly identical to the existing functions. I wonder why we
can't reuse them. In any case, I assume you know what you are doing from
the code integration point of view :-)

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/vgic/vgic.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 3d818a98ad..8aaad4bffa 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -722,6 +722,50 @@ bool vgic_evtchn_irq_pending(struct vcpu *v)
>      return pending;
>  }
>  
> +bool vgic_reserve_virq(struct domain *d, unsigned int virq)
> +{
> +    if ( virq >= vgic_num_irqs(d) )
> +        return false;
> +
> +    return !test_and_set_bit(virq, d->arch.vgic.allocated_irqs);
> +}
> +
> +int vgic_allocate_virq(struct domain *d, bool spi)
> +{
> +    int first, end;
> +    unsigned int virq;
> +
> +    if ( !spi )
> +    {
> +        /* We only allocate PPIs. SGIs are all reserved */
> +        first = 16;
> +        end = 32;
> +    }
> +    else
> +    {
> +        first = 32;
> +        end = vgic_num_irqs(d);
> +    }
> +
> +    /*
> +     * There is no spinlock to protect allocated_irqs, therefore
> +     * test_and_set_bit may fail. If so retry it.
> +     */
> +    do
> +    {
> +        virq = find_next_zero_bit(d->arch.vgic.allocated_irqs, end, first);
> +        if ( virq >= end )
> +            return -1;
> +    } while ( test_and_set_bit(virq, d->arch.vgic.allocated_irqs) );
> +
> +    return virq;
> +}
> +
> +void vgic_free_virq(struct domain *d, unsigned int virq)
> +{
> +    clear_bit(virq, d->arch.vgic.allocated_irqs);
> +}
> +
>  struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>                                        unsigned int virq)
>  {
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 30/39] ARM: new VGIC: Dump virtual IRQ info
  2018-03-21 16:32 ` [PATCH v3 30/39] ARM: new VGIC: Dump virtual IRQ info Andre Przywara
@ 2018-03-27 22:39   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:39 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> When we dump guest state on the Xen console, we also print the state of
> IRQs that are on a VCPU.
> Add the code to dump the state of an IRQ handled by the new VGIC.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Acked-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>

> ---
>  xen/arch/arm/vgic/vgic.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 8aaad4bffa..79c6a5553d 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -766,6 +766,31 @@ void vgic_free_virq(struct domain *d, unsigned int virq)
>      clear_bit(virq, d->arch.vgic.allocated_irqs);
>  }
>  
> +void gic_dump_vgic_info(struct vcpu *v)
> +{
> +    struct vgic_cpu *vgic_cpu = &v->arch.vgic;
> +    struct vgic_irq *irq;
> +    unsigned long flags;
> +
> +    spin_lock_irqsave(&v->arch.vgic.ap_list_lock, flags);
> +
> +    if ( !list_empty(&vgic_cpu->ap_list_head) )
> +        printk("   active or pending interrupts queued:\n");
> +
> +    list_for_each_entry ( irq, &vgic_cpu->ap_list_head, ap_list )
> +    {
> +        spin_lock(&irq->irq_lock);
> +        printk("     %s %s irq %u: %spending, %sactive, %senabled\n",
> +               irq->hw ? "hardware" : "virtual",
> +               irq->config == VGIC_CONFIG_LEVEL ? "level" : "edge",
> +               irq->intid, irq_is_pending(irq) ? "" : "not ",
> +               irq->active ? "" : "not ", irq->enabled ? "" : "not ");
> +        spin_unlock(&irq->irq_lock);
> +    }
> +
> +    spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
> +}
> +
>  struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>                                        unsigned int virq)
>  {
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 31/39] ARM: new VGIC: Provide system register emulation stub
  2018-03-21 16:32 ` [PATCH v3 31/39] ARM: new VGIC: Provide system register emulation stub Andre Przywara
@ 2018-03-27 22:40   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:40 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The Xen arch code traps system registers writes from the guest and will
> relay anything GIC related to the VGIC.
> Since this affects only GICv3 (which we don't yet emulate), provide a
> stub implementation of vgic_emulate() for now.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Acked-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>  xen/arch/arm/vgic/vgic.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 79c6a5553d..ffab0b2635 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -814,6 +814,13 @@ struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>      return desc;
>  }
>  
> +bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr)
> +{
> +    ASSERT(current->domain->arch.vgic.version == GIC_V3);
> +
> +    return false;
> +}
> +
>  /*
>   * was:
>   *      int kvm_vgic_map_phys_irq(struct vcpu *vcpu, u32 virt_irq, u32 phys_irq)
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 33/39] ARM: new VGIC: Add preliminary stub implementation
  2018-03-21 16:32 ` [PATCH v3 33/39] ARM: new VGIC: Add preliminary stub implementation Andre Przywara
@ 2018-03-27 22:48   ` Stefano Stabellini
  2018-04-03 13:22     ` Julien Grall
  0 siblings, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:48 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The ARM arch code requires an interrupt controller emulation to implement
> vgic_clear_pending_irqs(), although it is suspected that it is actually
> not necessary. Go with a stub for now to make the linker happy.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index 23b8abfc5e..b70fdaaecb 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -791,6 +791,14 @@ void gic_dump_vgic_info(struct vcpu *v)
>      spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
>  }
>  
> +void vgic_clear_pending_irqs(struct vcpu *v)
> +{
> +    /*
> +     * TODO: It is unclear whether we really need this, so we might instead
> +     * remove it on the caller site.
> +     */
> +}

This is OK for now.

However, thinking about this issue, is it possible for a vcpu to send an
interrupt to an offline vcpu, maybe an SGI? What would happen in that
case? It looks like that vgic_mmio_write_sgir would allow it. Otherwise,
a vcpu could cause the generation of a physical interrupt, an SPI,
targeting an offline vcpu.

Maybe we should WARN in case ap_list is not empty?


>  /**
>   * arch_move_irqs() - migrate the physical affinity of hardware mapped vIRQs
>   * @v:  the vCPU, already assigned to the new pCPU
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC
  2018-03-22  8:00   ` Julien Grall
  2018-03-22 11:18     ` Andre Przywara
@ 2018-03-27 22:50     ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:50 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Andre Przywara

On Thu, 22 Mar 2018, Julien Grall wrote:
> Hi Andre,
> 
> On 03/21/2018 04:32 PM, Andre Przywara wrote:
> > This patch implements the function which is called by Xen when it wants
> > to register the virtual GIC.
> > This also implements vgic_max_vcpus() for the new VGIC, which reports
> > back the maximum number of VCPUs a certain GIC model supports. Similar
> > to the counterpart in the "old" VGIC, we return some maximum value if
> > the VGIC has not been initialised yet.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> 
> Thank you for the update. We will have to remove the GIC_INVALID case once
> Andrew's series is merged. If his series is merged before yours, it would not
> be an issue as that case should never be hit.
> 
> So:
> 
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 35/39] ARM: new VGIC: Add vgic_v2_enable
  2018-03-21 16:32 ` [PATCH v3 35/39] ARM: new VGIC: Add vgic_v2_enable Andre Przywara
@ 2018-03-27 22:51   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 22:51 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> Enable the VGIC operation by properly initialising the registers
> in the hypervisor GIC interface.
> 
> This is based on Linux commit f7b6985cc3d0, written by Eric Auger.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Acked-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
> Changelog v2 ... v3:
> - replace "1" with "true" in boolean parameter
> 
> Changelog v1 ... v2:
> - move patch from later part in the series
> 
>  xen/arch/arm/vgic/vgic-v2.c | 6 ++++++
>  xen/arch/arm/vgic/vgic.h    | 1 +
>  2 files changed, 7 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c
> index 8ab0cfe81d..ce77e58857 100644
> --- a/xen/arch/arm/vgic/vgic-v2.c
> +++ b/xen/arch/arm/vgic/vgic-v2.c
> @@ -229,6 +229,12 @@ void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr)
>      gic_hw_ops->write_lr(lr, &lr_val);
>  }
>  
> +void vgic_v2_enable(struct vcpu *vcpu)
> +{
> +    /* Get the show on the road... */
> +    gic_hw_ops->update_hcr_status(GICH_HCR_EN, true);
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index a3fcd4d965..112952fbf9 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -66,6 +66,7 @@ void vgic_sync_hardware_irq(struct domain *d,
>  void vgic_v2_fold_lr_state(struct vcpu *vcpu);
>  void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct vcpu *vcpu);
> +void vgic_v2_enable(struct vcpu *vcpu);
>  int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
>                               enum vgic_type);
>  
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 38/39] ARM: new VGIC: Allocate two pages for struct vcpu
  2018-03-22  8:11   ` Julien Grall
@ 2018-03-27 23:07     ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 23:07 UTC (permalink / raw)
  To: Julien Grall; +Cc: xen-devel, Stefano Stabellini, Andre Przywara

On Thu, 22 Mar 2018, Julien Grall wrote:
> Hi Andre,
> 
> On 03/21/2018 04:32 PM, Andre Przywara wrote:
> > At the moment we allocate exactly one page for struct vcpu on ARM, also
> > have a check in place to prevent it growing beyond 4KB.
> > As the struct includes the state of all 32 private (per-VCPU) interrupts,
> > we are at 3840 bytes on arm64 at the moment already. Growing the per-IRQ
> > VGIC structure even slightly makes the VCPU quickly exceed the 4K limit.
> > The new VGIC will need more space per virtual IRQ. I spent a few hours
> > trying to trim this down, but couldn't get it below 4KB, even with the
> > nasty hacks piling up to save some bytes here and there.
> > It turns out that beyond efficiency, maybe, there is no real technical
> > reason this struct has to fit in one page, so lifting the limit to two
> > pages seems like the most pragmatic solution.
> > Restrict this to compiling with the new VGIC and for ARM64 only.
> > 
> > Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> > ---
> > Changelog v2 ... v3:
> > - rework alloc_vcpu_struct() to avoid nasty #ifdef
> > 
> > Changelog v1 ... v2:
> > - confine change to new VGIC and ARM64 only
> > 
> >   xen/arch/arm/domain.c | 25 +++++++++++++++++++++----
> >   1 file changed, 21 insertions(+), 4 deletions(-)
> > 
> > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> > index 9688e62f78..23bda3f7db 100644
> > --- a/xen/arch/arm/domain.c
> > +++ b/xen/arch/arm/domain.c
> > @@ -505,19 +505,36 @@ void dump_pageframe_info(struct domain *d)
> >     }
> >   +/*
> > + * The new VGIC has a bigger per-IRQ structure, so we need more than one
> > + * page on ARM64. Cowardly increase the limit in this case.
> > + */
> > +#if defined(CONFIG_NEW_VGIC) && defined(CONFIG_ARM_64)
> > +#define PAGES_PER_VCPU  2
> > +#else
> > +#define PAGES_PER_VCPU  1
> > +#endif
> > +
> >   struct vcpu *alloc_vcpu_struct(void)
> >   {
> >       struct vcpu *v;
> > -    BUILD_BUG_ON(sizeof(*v) > PAGE_SIZE);
> > -    v = alloc_xenheap_pages(0, 0);
> > +
> > +    BUILD_BUG_ON(sizeof(*v) > PAGES_PER_VCPU * PAGE_SIZE);
> > +    v = alloc_xenheap_pages(get_order_from_pages(PAGES_PER_VCPU), 0);
> 
> I was suggesting to use get_order_from_pages(sizeof (...)) so if we end up to
> be smaller, you don't lose a page for nothing. But I am ok with that too and
> can revisit later. So:
> 
> Acked-by: Julien Grall <julien.grall@arm.com>

That is actually a good suggestion, let's not lose track of it.

With that fix:

Acked-by: Stefano Stabellini <sstabellini@kernel.org>



> >       if ( v != NULL )
> > -        clear_page(v);
> > +    {
> > +        unsigned int i;
> > +
> > +        for ( i = 0; i < PAGES_PER_VCPU; i++ )
> > +            clear_page((void *)v + i * PAGE_SIZE);
> > +    }
> > +
> >       return v;
> >   }
> >     void free_vcpu_struct(struct vcpu *v)
> >   {
> > -    free_xenheap_page(v);
> > +    free_xenheap_pages(v, get_order_from_pages(PAGES_PER_VCPU));
> >   }
> >     int vcpu_initialise(struct vcpu *v)
> > 
 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 37/39] ARM: new VGIC: vgic-init: implement map_resources
  2018-03-21 16:32 ` [PATCH v3 37/39] ARM: new VGIC: vgic-init: implement map_resources Andre Przywara
@ 2018-03-27 23:09   ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 23:09 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> map_resources is the last initialization step needed before the first
> VCPU is run. At that stage the code stores the MMIO base addresses used.
> Also it registers the respective register frames with the MMIO framework.
> 
> This is based on Linux commit cbae53e663ea, written by Eric Auger.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Acked-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic-v2.c | 66 +++++++++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic/vgic.h    |  1 +
>  2 files changed, 67 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c
> index ce77e58857..5516a8534f 100644
> --- a/xen/arch/arm/vgic/vgic-v2.c
> +++ b/xen/arch/arm/vgic/vgic-v2.c
> @@ -235,6 +235,72 @@ void vgic_v2_enable(struct vcpu *vcpu)
>      gic_hw_ops->update_hcr_status(GICH_HCR_EN, true);
>  }
>  
> +int vgic_v2_map_resources(struct domain *d)
> +{
> +    struct vgic_dist *dist = &d->arch.vgic;
> +    paddr_t cbase, csize;
> +    paddr_t vbase;
> +    int ret;
> +
> +    /*
> +     * The hardware domain gets the hardware address.
> +     * Guests get the virtual platform layout.
> +     */
> +    if ( is_hardware_domain(d) )
> +    {
> +        d->arch.vgic.vgic_dist_base = gic_v2_hw_data.dbase;
> +        /*
> +         * For the hardware domain, we always map the whole HW CPU
> +         * interface region in order to match the device tree (the "reg"
> +         * properties is copied as it is).
> +         * Note that we assume the size of the CPU interface is always
> +         * aligned to PAGE_SIZE.
> +         */
> +        cbase = gic_v2_hw_data.cbase; /* was: dist->vgic_cpu_base */
> +        csize = gic_v2_hw_data.csize;
> +        vbase = gic_v2_hw_data.vbase; /* was: kvm_vgic_global_state.vcpu_base */

NIT: do we really need "was: kvm_vgic_global_state.vcpu_base" here?


> +    }
> +    else
> +    {
> +        d->arch.vgic.vgic_dist_base = GUEST_GICD_BASE;
> +        /*
> +         * The CPU interface exposed to the guest is always 8kB. We may
> +         * need to add an offset to the virtual CPU interface base
> +         * address when in the GIC is aliased to get a 8kB contiguous
> +         * region.
> +         */
> +        BUILD_BUG_ON(GUEST_GICC_SIZE != SZ_8K);
> +        cbase = GUEST_GICC_BASE;
> +        csize = GUEST_GICC_SIZE;
> +        vbase = gic_v2_hw_data.vbase + gic_v2_hw_data.aliased_offset;
> +    }
> +
> +
> +    ret = vgic_register_dist_iodev(d, gaddr_to_gfn(dist->vgic_dist_base),
> +                                   VGIC_V2);
> +    if ( ret )
> +    {
> +        gdprintk(XENLOG_ERR, "Unable to register VGIC MMIO regions\n");
> +        return ret;
> +    }
> +
> +    /*
> +     * Map the gic virtual cpu interface in the gic cpu interface
> +     * region of the guest.
> +     */
> +    ret = map_mmio_regions(d, gaddr_to_gfn(cbase), csize / PAGE_SIZE,
> +                           maddr_to_mfn(vbase));
> +    if ( ret )
> +    {
> +        gdprintk(XENLOG_ERR, "Unable to remap VGIC CPU to VCPU\n");
> +        return ret;
> +    }
> +
> +    dist->ready = true;
> +
> +        return 0;

Code style

With these fixed:

Acked-by: Stefano Stabellini <sstabellini@kernel.org>



> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
> index 112952fbf9..e8e407adbe 100644
> --- a/xen/arch/arm/vgic/vgic.h
> +++ b/xen/arch/arm/vgic/vgic.h
> @@ -67,6 +67,7 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu);
>  void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr);
>  void vgic_v2_set_underflow(struct vcpu *vcpu);
>  void vgic_v2_enable(struct vcpu *vcpu);
> +int vgic_v2_map_resources(struct domain *d);
>  int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn,
>                               enum vgic_type);
>  
> -- 
> 2.14.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init
  2018-03-21 16:32 ` [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init Andre Przywara
  2018-03-22  8:01   ` Julien Grall
@ 2018-03-27 23:16   ` Stefano Stabellini
  2018-03-28  0:06     ` Stefano Stabellini
  2018-03-28 10:49     ` Andre Przywara
  1 sibling, 2 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-27 23:16 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> This patch allocates and initializes the data structures used to model
> the vgic distributor and virtual cpu interfaces. At that stage the
> number of IRQs and number of virtual CPUs is frozen.
> Implement the various functions that the Xen arch code is expecting to
> call during domain and VCPU setup to initialize the VGIC.
> Their prototypes are already in existing header files.
> 
> This is based on Linux commit ad275b8bb1e6, written by Eric Auger.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> Changelog v2 ... v3:
> - move ROUNDUP(nr_spis) call before boundary check
> 
> Changelog v1 ... v2:
> - remove stray kvm_ prefix in comment
> - use unsigned int
> - ROUNDUP number of SPIs
> - fix indentation
> 
>  xen/arch/arm/vgic/vgic-init.c | 201 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 201 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
> index d091c92ed0..bfd3d09edb 100644
> --- a/xen/arch/arm/vgic/vgic-init.c
> +++ b/xen/arch/arm/vgic/vgic-init.c
> @@ -15,11 +15,83 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <xen/lib.h>
>  #include <xen/sched.h>
>  #include <asm/new_vgic.h>
>  
>  #include "vgic.h"
>  
> +/*
> + * Initialization rules: there are multiple stages to the vgic
> + * initialization, both for the distributor and the CPU interfaces.  The basic
> + * idea is that even though the VGIC is not functional or not requested from
> + * user space, the critical path of the run loop can still call VGIC functions
> + * that just won't do anything, without them having to check additional
> + * initialization flags to ensure they don't look at uninitialized data
> + * structures.
> + *
> + * Distributor:
> + *
> + * - vgic_early_init(): initialization of static data that doesn't
> + *   depend on any sizing information or emulation type. No allocation
> + *   is allowed there.
> + *
> + * - vgic_init(): allocation and initialization of the generic data
> + *   structures that depend on sizing information (number of CPUs,
> + *   number of interrupts). Also initializes the vcpu specific data
> + *   structures. Can be executed lazily for GICv2.
> + *
> + * CPU Interface:
> + *
> + * - vgic_vcpu_early_init(): initialization of static data that
> + *   doesn't depend on any sizing information or emulation type. No
> + *   allocation is allowed there.
> + */
> +
> +/**
> + * vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
> + * @vcpu: The VCPU whose VGIC data structures whould be initialized
> + *
> + * Only do initialization, but do not actually enable the VGIC CPU interface
> + * yet.
> + */
> +static void vgic_vcpu_early_init(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +    unsigned int i;
> +
> +    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +    spin_lock_init(&vgic_cpu->ap_list_lock);
> +
> +    /*
> +     * Enable and configure all SGIs to be edge-triggered and
> +     * configure all PPIs as level-triggered.
> +     */
> +    for ( i = 0; i < VGIC_NR_PRIVATE_IRQS; i++ )
> +    {
> +        struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
> +
> +        INIT_LIST_HEAD(&irq->ap_list);
> +        spin_lock_init(&irq->irq_lock);
> +        irq->intid = i;
> +        irq->vcpu = NULL;
> +        irq->target_vcpu = vcpu;
> +        irq->targets = 1U << vcpu->vcpu_id;
> +        atomic_set(&irq->refcount, 0);
> +        if ( vgic_irq_is_sgi(i) )
> +        {
> +            /* SGIs */
> +            irq->enabled = 1;
> +            irq->config = VGIC_CONFIG_EDGE;
> +        }
> +        else
> +        {
> +            /* PPIs */
> +            irq->config = VGIC_CONFIG_LEVEL;
> +        }
> +    }
> +}
> +
>  /* CREATION */
>  
>  /**
> @@ -50,6 +122,135 @@ int domain_vgic_register(struct domain *d, int *mmio_count)
>      return 0;
>  }
>  
> +/* INIT/DESTROY */
> +
> +/**
> + * domain_vgic_init: initialize the dist data structures
> + * @d: domain pointer
> + * @nr_spis: number of SPIs
> + */
> +int domain_vgic_init(struct domain *d, unsigned int nr_spis)
> +{
> +    struct vgic_dist *dist = &d->arch.vgic;
> +    unsigned int i;
> +    int ret;
> +
> +    /* The number of SPIs must be a multiple of 32 per the GIC spec. */
> +    nr_spis = ROUNDUP(nr_spis, 32);
> +
> +    /* Limit the number of virtual SPIs supported to (1020 - 32) = 988  */
> +    if ( nr_spis > (1020 - NR_LOCAL_IRQS) )
> +        return -EINVAL;
> +
> +    dist->nr_spis = nr_spis;
> +    dist->spis = xzalloc_array(struct vgic_irq, nr_spis);
> +    if ( !dist->spis )
> +        return  -ENOMEM;
> +
> +    /*
> +     * In the following code we do not take the irq struct lock since
> +     * no other action on irq structs can happen while the VGIC is
> +     * not initialized yet:
> +     * If someone wants to inject an interrupt or does a MMIO access, we
> +     * require prior initialization in case of a virtual GICv3 or trigger
> +     * initialization when using a virtual GICv2.
> +     */
> +    for ( i = 0; i < nr_spis; i++ )
> +    {
> +        struct vgic_irq *irq = &dist->spis[i];
> +
> +        irq->intid = i + VGIC_NR_PRIVATE_IRQS;
> +        INIT_LIST_HEAD(&irq->ap_list);
> +        spin_lock_init(&irq->irq_lock);
> +        irq->vcpu = NULL;
> +        irq->target_vcpu = NULL;
> +        atomic_set(&irq->refcount, 0);
> +        if ( dist->version == GIC_V2 )
> +            irq->targets = 0;
> +        else
> +            irq->mpidr = 0;
> +    }
> +
> +    INIT_LIST_HEAD(&dist->lpi_list_head);
> +    spin_lock_init(&dist->lpi_list_lock);
> +
> +    if ( dist->version == GIC_V2 )
> +        ret = vgic_v2_map_resources(d);
> +    else
> +        ret = -ENXIO;
> +
> +    if ( ret )
> +        return ret;
> +
> +    /* allocated_irqs() is used by Xen to find available vIRQs */
> +    d->arch.vgic.allocated_irqs =
> +        xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d)));
> +    if ( !d->arch.vgic.allocated_irqs )
> +        return -ENOMEM;
> +
> +    /* vIRQ0-15 (SGIs) are reserved */
> +    for ( i = 0; i < NR_GIC_SGI; i++ )
> +        set_bit(i, d->arch.vgic.allocated_irqs);
> +
> +    return 0;
> +}
> +
> +/**
> + * vcpu_vgic_init() - Register VCPU-specific KVM iodevs
> + * was: kvm_vgic_vcpu_init()

Is this "was: kvm_vgic_vcpu_init" really helpful?

In any case

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> + * Xen: adding vgic_vx_enable() call
> + * @vcpu: pointer to the VCPU being created and initialized
> + */
> +int vcpu_vgic_init(struct vcpu *vcpu)
> +{
> +    int ret = 0;
> +
> +    vgic_vcpu_early_init(vcpu);
> +
> +    if ( gic_hw_version() == GIC_V2 )
> +        vgic_v2_enable(vcpu);
> +    else
> +        ret = -ENXIO;
> +
> +    return ret;
> +}
> +
> +void domain_vgic_free(struct domain *d)
> +{
> +    struct vgic_dist *dist = &d->arch.vgic;
> +        int i, ret;
> +
> +    for ( i = 0; i < dist->nr_spis; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(d, NULL, 32 + i);
> +
> +        if ( !irq->hw )
> +            continue;
> +
> +        ret = release_guest_irq(d, irq->hwintid);
> +        if ( ret )
> +            dprintk(XENLOG_G_WARNING,
> +                    "d%u: Failed to release virq %u ret = %d\n",
> +                    d->domain_id, 32 + i, ret);
> +    }
> +
> +    dist->ready = false;
> +    dist->initialized = false;
> +
> +    xfree(dist->spis);
> +    xfree(dist->allocated_irqs);
> +    dist->nr_spis = 0;
> +}
> +
> +int vcpu_vgic_free(struct vcpu *vcpu)
> +{
> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> +
> +    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> +
> +    return 0;
> +}
> +
>  /*
>   * Local variables:
>   * mode: C

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-21 16:32 ` [PATCH v3 06/39] ARM: evtchn: " Andre Przywara
  2018-03-22  2:08   ` Julien Grall
  2018-03-26 20:08   ` Stefano Stabellini
@ 2018-03-28  0:01   ` Stefano Stabellini
  2018-03-28 15:39     ` Andre Przywara
  2018-04-03 13:34     ` Julien Grall
  2 siblings, 2 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-28  0:01 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> The event channel IRQ has level triggered semantics, however the current
> VGIC treats everything as edge triggered.
> To correctly process those IRQs, we have to lower the (virtual) IRQ line
> at some point in time, depending on whether ther interrupt condition
> still prevails.
> Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
> line match its status, and call this function upon every hypervisor
> entry.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/domain.c       | 7 +++++++
>  xen/arch/arm/traps.c        | 1 +
>  xen/include/asm-arm/event.h | 1 +
>  3 files changed, 9 insertions(+)
> 
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index ff97f2bc76..9688e62f78 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
>      vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
>  }
>  
> +void vcpu_update_evtchn_irq(struct vcpu *v)
> +{
> +    bool pending = vcpu_info(v, evtchn_upcall_pending);
> +
> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
> +}
> +
>  /* The ARM spec declares that even if local irqs are masked in
>   * the CPSR register, an irq should wake up a cpu from WFI anyway.
>   * For this reason we need to check for irqs that need delivery,
> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> index 2638446693..5c18e918b0 100644
> --- a/xen/arch/arm/traps.c
> +++ b/xen/arch/arm/traps.c
> @@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
>           * trap and how it can be optimised.
>           */
>          vtimer_update_irqs(current);
> +        vcpu_update_evtchn_irq(current);
>  #endif

I am replying to this patch, even though I have already committed it, to
point out a problem with the way we currently handle the evtchn_irq in
this series.

The short version is that I think we should configure the PPI
corresponding to the evtchn_irq as EDGE instead of LEVEL.

The long explanation follows, please correct me if I am wrong.

1) vcpuA/cpuA is running, it has already handled the event, cleared
evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
Xen yet. It is still in guest mode.

2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
vgic_inject_irq. However, because irq->line_level is high, it is not
injected.

3) vcpuA has to wait until trapping into Xen, calling
vcpu_update_evtchn_irq, and going back to guest mode before receiving
the event. This is theoretically a very long time.


Instead what should happen is:

1) vcpuA/cpuA is running, it has already handled the event, cleared
evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
Xen yet. It is still in guest mode.

2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
vgic_inject_irq, which calls vgic_queue_irq_unlock that
vcpu_kick(vcpuA), forcing it to take the event immediately.

Am I right? Wouldn't it be safer to continue configuring the evtchn_irq
as edge even in the new vgic?

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init
  2018-03-27 23:16   ` Stefano Stabellini
@ 2018-03-28  0:06     ` Stefano Stabellini
  2018-03-28 10:49     ` Andre Przywara
  1 sibling, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-28  0:06 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall, Andre Przywara

On Tue, 27 Mar 2018, Stefano Stabellini wrote:
> > +static void vgic_vcpu_early_init(struct vcpu *vcpu)
> > +{
> > +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
> > +    unsigned int i;
> > +
> > +    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
> > +    spin_lock_init(&vgic_cpu->ap_list_lock);
> > +
> > +    /*
> > +     * Enable and configure all SGIs to be edge-triggered and
> > +     * configure all PPIs as level-triggered.
> > +     */
> > +    for ( i = 0; i < VGIC_NR_PRIVATE_IRQS; i++ )
> > +    {
> > +        struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
> > +
> > +        INIT_LIST_HEAD(&irq->ap_list);
> > +        spin_lock_init(&irq->irq_lock);
> > +        irq->intid = i;
> > +        irq->vcpu = NULL;
> > +        irq->target_vcpu = vcpu;
> > +        irq->targets = 1U << vcpu->vcpu_id;
> > +        atomic_set(&irq->refcount, 0);
> > +        if ( vgic_irq_is_sgi(i) )
> > +        {
> > +            /* SGIs */
> > +            irq->enabled = 1;
> > +            irq->config = VGIC_CONFIG_EDGE;
> > +        }
> > +        else
> > +        {
> > +            /* PPIs */
> > +            irq->config = VGIC_CONFIG_LEVEL;

Please see my comment about evtchn_irq being edge:

alpine.DEB.2.10.1803271651150.12360@sstabellini-ThinkPad-X260


> > +        }
> > +    }
> > +}


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers
  2018-03-27 21:06   ` Stefano Stabellini
@ 2018-03-28  9:09     ` Andre Przywara
  2018-03-28 17:19       ` Stefano Stabellini
  0 siblings, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-28  9:09 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 27/03/18 22:06, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> As the enable register handlers are shared between the v2 and v3
>> emulation, their implementation goes into vgic-mmio.c, to be easily
>> referenced from the v3 emulation as well later.
>> This introduces a vgic_sync_hardware_irq() function, which updates the
>> physical side of a hardware mapped virtual IRQ.
>> Because the existing locking order between vgic_irq->irq_lock and
>> irq_desc->lock dictates so, we drop the irq_lock and retake them in the
>> proper order.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>> ---
>> Changelog v2 ... v3:
>> - fix indentation
>> - fix wording in comment
>> - add Reviewed-by:
>>
>> Changelog v1 ... v2:
>> - ASSERT on h/w IRQ and vIRQ staying in sync
>>
>>  xen/arch/arm/vgic/vgic-mmio-v2.c |   4 +-
>>  xen/arch/arm/vgic/vgic-mmio.c    | 117 +++++++++++++++++++++++++++++++++++++++
>>  xen/arch/arm/vgic/vgic-mmio.h    |  11 ++++
>>  xen/arch/arm/vgic/vgic.c         |  40 +++++++++++++
>>  xen/arch/arm/vgic/vgic.h         |   3 +
>>  5 files changed, 173 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> index 43c1ab5906..7efd1c4eb4 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
>> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> @@ -89,10 +89,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>          vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
>> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> +        vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
>> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> +        vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
>>          vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
>> index a03e8d88b9..f219b7c509 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio.c
>> +++ b/xen/arch/arm/vgic/vgic-mmio.c
>> @@ -39,6 +39,123 @@ void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>>      /* Ignore */
>>  }
>>  
>> +/*
>> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
>> + * of the enabled bit, so there is only one function for both here.
>> + */
>> +unsigned long vgic_mmio_read_enable(struct vcpu *vcpu,
>> +                                    paddr_t addr, unsigned int len)
>> +{
>> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +    uint32_t value = 0;
>> +    unsigned int i;
>> +
>> +    /* Loop over all IRQs affected by this read */
>> +    for ( i = 0; i < len * 8; i++ )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
>> +
>> +        if ( irq->enabled )
>> +            value |= (1U << i);
> 
> Don't we need to take the irq->irq_lock before reading irq->enabled?

Not really. A boolean has no illegal state, so we can't read any
intermediate values.

If you think about concurrent writes: That is even racy on real
hardware, and normally you expect a sane driver to take a lock around
every distributor access (cf. spin_lock(&gicv2.lock)).
Keep in mind that only a guest can change the enabled state.

So the rationale behind those unlocked reads is:
As long as it doesn't harm the hypervisor, we don't care too much about
being 100% correct in a situation that is out of spec anyway.
We discussed this issue also with Julien before:
https://lists.xen.org/archives/html/xen-devel/2018-02/msg02148.html

Cheers,
Andre.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 29/39] ARM: new VGIC: Handle virtual IRQ allocation/reservation
  2018-03-27 22:38   ` Stefano Stabellini
@ 2018-03-28  9:17     ` Andre Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-28  9:17 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 27/03/18 23:38, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> To find an unused virtual IRQ number Xen uses a scheme to track used
>> virtual IRQs.
>> Implement this interface in the new VGIC to make the Xen core/arch code
>> happy.
>> This is actually somewhat VGIC agnostic, so is mostly a copy of the code
>> from the old VGIC. But it has to live in the VGIC files, so we can't
>> easily reuse the existing implementation.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Acked-by: Julien Grall <julien.grall@arm.com>
> 
> These are exactly identical to the existing functions. I wonder why we
> can't reuse them. In any case, I assume you know what you are doing from
> the code integration point of view :-)

They are, but there is no real shared VGIC code at the moment, and I
didn't want to introduce anything just for those simple functions,
especially with the prospect of the existing code going away anyway later.

> Acked-by: Stefano Stabellini <sstabellini@kernel.org>

Thanks!
Andre.

> 
> 
>> ---
>>  xen/arch/arm/vgic/vgic.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 44 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index 3d818a98ad..8aaad4bffa 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -722,6 +722,50 @@ bool vgic_evtchn_irq_pending(struct vcpu *v)
>>      return pending;
>>  }
>>  
>> +bool vgic_reserve_virq(struct domain *d, unsigned int virq)
>> +{
>> +    if ( virq >= vgic_num_irqs(d) )
>> +        return false;
>> +
>> +    return !test_and_set_bit(virq, d->arch.vgic.allocated_irqs);
>> +}
>> +
>> +int vgic_allocate_virq(struct domain *d, bool spi)
>> +{
>> +    int first, end;
>> +    unsigned int virq;
>> +
>> +    if ( !spi )
>> +    {
>> +        /* We only allocate PPIs. SGIs are all reserved */
>> +        first = 16;
>> +        end = 32;
>> +    }
>> +    else
>> +    {
>> +        first = 32;
>> +        end = vgic_num_irqs(d);
>> +    }
>> +
>> +    /*
>> +     * There is no spinlock to protect allocated_irqs, therefore
>> +     * test_and_set_bit may fail. If so retry it.
>> +     */
>> +    do
>> +    {
>> +        virq = find_next_zero_bit(d->arch.vgic.allocated_irqs, end, first);
>> +        if ( virq >= end )
>> +            return -1;
>> +    } while ( test_and_set_bit(virq, d->arch.vgic.allocated_irqs) );
>> +
>> +    return virq;
>> +}
>> +
>> +void vgic_free_virq(struct domain *d, unsigned int virq)
>> +{
>> +    clear_bit(virq, d->arch.vgic.allocated_irqs);
>> +}
>> +
>>  struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>>                                        unsigned int virq)
>>  {
>> -- 
>> 2.14.1
>>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 16/39] ARM: new VGIC: Add MMIO handling framework
  2018-03-27 20:07   ` Stefano Stabellini
@ 2018-03-28  9:28     ` Andre Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-28  9:28 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 27/03/18 21:07, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> Add an MMIO handling framework to the VGIC emulation:
>> Each register is described by its offset, size (or number of bits per
>> IRQ, if applicable) and the read/write handler functions. We provide
>> initialization macros to describe each GIC register later easily.
>>
>> Separate dispatch functions for read and write accesses are connected
>> to Xen's MMIO handling framework and binary-search for the responsible
>> register handler based on the offset address within the region.
>>
>> The register handler prototype are courtesy of Christoffer Dall.
>>
>> This is based on Linux commit 4493b1c4866a, written by Marc Zyngier.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
> 
> Acked-by: Stefano Stabellini <sstabellini@kernel.org>

Thanks!

> 
> One comment below (the ack still stands anyway).
> 
>> ---
>>  xen/arch/arm/vgic/vgic-mmio.c | 180 ++++++++++++++++++++++++++++++++++++++++++
>>  xen/arch/arm/vgic/vgic-mmio.h |  89 +++++++++++++++++++++
>>  2 files changed, 269 insertions(+)
>>  create mode 100644 xen/arch/arm/vgic/vgic-mmio.c
>>  create mode 100644 xen/arch/arm/vgic/vgic-mmio.h
>>
>> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
>> new file mode 100644
>> index 0000000000..866023a84d
>> --- /dev/null
>> +++ b/xen/arch/arm/vgic/vgic-mmio.c
>> @@ -0,0 +1,180 @@
>> +/*
>> + * VGIC MMIO handling functions
>> + * Imported from Linux ("new" KVM VGIC) and heavily adapted to Xen.
>> + *
>> + * 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.
>> + */
>> +
>> +#include <xen/bitops.h>
>> +#include <xen/lib.h>
>> +#include <xen/sched.h>
>> +#include <asm/new_vgic.h>
>> +#include <asm/byteorder.h>
>> +
>> +#include "vgic.h"
>> +#include "vgic-mmio.h"
>> +
>> +unsigned long vgic_mmio_read_raz(struct vcpu *vcpu,
>> +                                 paddr_t addr, unsigned int len)
>> +{
>> +    return 0;
>> +}
>> +
>> +unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
>> +                                 paddr_t addr, unsigned int len)
>> +{
>> +    return -1UL;
>> +}
>> +
>> +void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>> +                        unsigned int len, unsigned long val)
>> +{
>> +    /* Ignore */
>> +}
> 
> Would these make sense a static inline?

We take function pointers to those functions.

Besides: are you really concerned about performance of write_ignore? ;-)

Cheers,
Andre.

>> +static int match_region(const void *key, const void *elt)
>> +{
>> +    const unsigned int offset = (unsigned long)key;
>> +    const struct vgic_register_region *region = elt;
>> +
>> +    if ( offset < region->reg_offset )
>> +        return -1;
>> +
>> +    if ( offset >= region->reg_offset + region->len )
>> +        return 1;
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct vgic_register_region *
>> +vgic_find_mmio_region(const struct vgic_register_region *regions,
>> +                      int nr_regions, unsigned int offset)
>> +{
>> +    return bsearch((void *)(uintptr_t)offset, regions, nr_regions,
>> +                   sizeof(regions[0]), match_region);
>> +}
>> +
>> +static bool check_region(const struct domain *d,
>> +                         const struct vgic_register_region *region,
>> +                         paddr_t addr, int len)
>> +{
>> +    unsigned int flags, nr_irqs = d->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +
>> +    switch ( len )
>> +    {
>> +    case sizeof(uint8_t):
>> +        flags = VGIC_ACCESS_8bit;
>> +        break;
>> +    case sizeof(uint32_t):
>> +        flags = VGIC_ACCESS_32bit;
>> +        break;
>> +    case sizeof(uint64_t):
>> +        flags = VGIC_ACCESS_64bit;
>> +        break;
>> +    default:
>> +        return false;
>> +    }
>> +
>> +    if ( (region->access_flags & flags) && IS_ALIGNED(addr, len) )
>> +    {
>> +        if ( !region->bits_per_irq )
>> +            return true;
>> +
>> +        /* Do we access a non-allocated IRQ? */
>> +        return VGIC_ADDR_TO_INTID(addr, region->bits_per_irq) < nr_irqs;
>> +    }
>> +
>> +    return false;
>> +}
>> +
>> +static const struct vgic_register_region *
>> +vgic_get_mmio_region(struct vcpu *vcpu, struct vgic_io_device *iodev,
>> +                     paddr_t addr, unsigned int len)
>> +{
>> +    const struct vgic_register_region *region;
>> +
>> +    region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
>> +                                   addr - gfn_to_gaddr(iodev->base_fn));
>> +    if ( !region || !check_region(vcpu->domain, region, addr, len) )
>> +        return NULL;
>> +
>> +    return region;
>> +}
>> +
>> +static int dispatch_mmio_read(struct vcpu *vcpu, mmio_info_t *info,
>> +                              register_t *r, void *priv)
>> +{
>> +    struct vgic_io_device *iodev = priv;
>> +    const struct vgic_register_region *region;
>> +    unsigned long data = 0;
>> +    paddr_t addr = info->gpa;
>> +    int len = 1U << info->dabt.size;
>> +
>> +    region = vgic_get_mmio_region(vcpu, iodev, addr, len);
>> +    if ( !region )
>> +    {
>> +        memset(r, 0, len);
>> +        return 0;
>> +    }
>> +
>> +    switch (iodev->iodev_type)
>> +    {
>> +    case IODEV_DIST:
>> +        data = region->read(vcpu, addr, len);
>> +        break;
>> +    case IODEV_REDIST:
>> +        data = region->read(iodev->redist_vcpu, addr, len);
>> +        break;
>> +    }
>> +
>> +    memcpy(r, &data, len);
>> +
>> +    return 1;
>> +}
>> +
>> +static int dispatch_mmio_write(struct vcpu *vcpu, mmio_info_t *info,
>> +                               register_t r, void *priv)
>> +{
>> +    struct vgic_io_device *iodev = priv;
>> +    const struct vgic_register_region *region;
>> +    unsigned long data = r;
>> +    paddr_t addr = info->gpa;
>> +    int len = 1U << info->dabt.size;
>> +
>> +    region = vgic_get_mmio_region(vcpu, iodev, addr, len);
>> +    if ( !region )
>> +        return 0;
>> +
>> +    switch (iodev->iodev_type)
>> +    {
>> +    case IODEV_DIST:
>> +        region->write(vcpu, addr, len, data);
>> +        break;
>> +    case IODEV_REDIST:
>> +        region->write(iodev->redist_vcpu, addr, len, data);
>> +        break;
>> +    }
>> +
>> +    return 1;
>> +}
>> +
>> +struct mmio_handler_ops vgic_io_ops = {
>> +    .read = dispatch_mmio_read,
>> +    .write = dispatch_mmio_write,
>> +};
>> +
>> +/*
>> + * Local variables:
>> + * mode: C
>> + * c-file-style: "BSD"
>> + * c-basic-offset: 4
>> + * indent-tabs-mode: nil
>> + * End:
>> + */
>> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
>> new file mode 100644
>> index 0000000000..bf062a27ca
>> --- /dev/null
>> +++ b/xen/arch/arm/vgic/vgic-mmio.h
>> @@ -0,0 +1,89 @@
>> +/*
>> + * Copyright (C) 2015, 2016 ARM Ltd.
>> + *
>> + * 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 __XEN_ARM_VGIC_VGIC_MMIO_H__
>> +#define __XEN_ARM_VGIC_VGIC_MMIO_H__
>> +
>> +struct vgic_register_region {
>> +    unsigned int reg_offset;
>> +    unsigned int len;
>> +    unsigned int bits_per_irq;
>> +    unsigned int access_flags;
>> +    unsigned long (*read)(struct vcpu *vcpu, paddr_t addr,
>> +                          unsigned int len);
>> +    void (*write)(struct vcpu *vcpu, paddr_t addr,
>> +                  unsigned int len, unsigned long val);
>> +};
>> +
>> +extern struct mmio_handler_ops vgic_io_ops;
>> +
>> +#define VGIC_ACCESS_8bit    1
>> +#define VGIC_ACCESS_32bit   2
>> +#define VGIC_ACCESS_64bit   4
>> +
>> +/*
>> + * Generate a mask that covers the number of bytes required to address
>> + * up to 1024 interrupts, each represented by <bits> bits. This assumes
>> + * that <bits> is a power of two.
>> + */
>> +#define VGIC_ADDR_IRQ_MASK(bits) (((bits) * 1024 / 8) - 1)
>> +
>> +/*
>> + * (addr & mask) gives us the _byte_ offset for the INT ID.
>> + * We multiply this by 8 the get the _bit_ offset, then divide this by
>> + * the number of bits to learn the actual INT ID.
>> + * But instead of a division (which requires a "long long div" implementation),
>> + * we shift by the binary logarithm of <bits>.
>> + * This assumes that <bits> is a power of two.
>> + */
>> +#define VGIC_ADDR_TO_INTID(addr, bits)  (((addr) & VGIC_ADDR_IRQ_MASK(bits)) * \
>> +                                         8 >> ilog2(bits))
>> +
>> +/*
>> + * Some VGIC registers store per-IRQ information, with a different number
>> + * of bits per IRQ. For those registers this macro is used.
>> + * The _WITH_LENGTH version instantiates registers with a fixed length
>> + * and is mutually exclusive with the _PER_IRQ version.
>> + */
>> +#define REGISTER_DESC_WITH_BITS_PER_IRQ(off, rd, wr, bpi, acc)  \
>> +    {                                                           \
>> +        .reg_offset = off,                                      \
>> +        .bits_per_irq = bpi,                                    \
>> +        .len = bpi * 1024 / 8,                                  \
>> +        .access_flags = acc,                                    \
>> +        .read = rd,                                             \
>> +        .write = wr,                                            \
>> +    }
>> +
>> +#define REGISTER_DESC_WITH_LENGTH(off, rd, wr, length, acc)     \
>> +    {                                                           \
>> +        .reg_offset = off,                                      \
>> +        .bits_per_irq = 0,                                      \
>> +        .len = length,                                          \
>> +        .access_flags = acc,                                    \
>> +        .read = rd,                                             \
>> +        .write = wr,                                            \
>> +    }
>> +
>> +unsigned long vgic_mmio_read_raz(struct vcpu *vcpu,
>> +                                 paddr_t addr, unsigned int len);
>> +
>> +unsigned long vgic_mmio_read_rao(struct vcpu *vcpu,
>> +                                 paddr_t addr, unsigned int len);
>> +
>> +void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
>> +                        unsigned int len, unsigned long val);
>> +
>> +#endif
>> -- 
>> 2.14.1
>>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers
  2018-03-27 20:38   ` Stefano Stabellini
@ 2018-03-28 10:36     ` Andre Przywara
  2018-03-28 17:20       ` Stefano Stabellini
  2018-03-28 17:22       ` [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers Stefano Stabellini
  0 siblings, 2 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-28 10:36 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: marc.zyngier, xen-devel, Julien Grall

Hi,

On 27/03/18 21:38, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> Those three registers are v2 emulation specific, so their implementation
>> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
>> as their implementation is pretty simple.
>> We choose to piggy-back on the existing KVM identification registers,
>> but use a different variant (major revision).
> 
> CC'ing Marc.
> 
> Reusing the KVM product ID could cause issues, for instance we could
> clash with KVM if Linux changes the Major number. If we were to actually
> reuse KVM's PRODUCT_ID we would need a better coordination in place.

Marc is aware of this, as this approach was decided after a brief
discussion with Julien and him last week.
If we need a quirk on the (guest) GIC driver side for the KVM VGIC, KVM
would bump the revision number, not the variant.
This is a good as coordination can realistically ever get.

> I suggest to either introduce a Xen specific PRODUCT_ID,

This is a bit of a stretch. Firstly, by the nature of this port the two
implementations are really close. Secondly: we can't really just occupy
any product ID. Technically the "K" isn't even reserved, but this ship
has sailed, so we could just piggy back on that for simplicity.

> or simply reuse
> the hardware value like the old vgic does for now. We can fix this
> later.

This implementation is totally different from anything existing. And we
don't want the guest to apply any errata fixes for the particular
hardware GIC. So using the hardware ID is not the best idea.

Cheers,
Andre

> In fact, I would be happy to swith to KVM's product id after appropriate
> discussions with the KVM community. At the very least, it would need to
> be written down somewhere under docs/ and/or Documentation.
> 
> Marc, what do you think?
> 
> 
>> When the guest enables the distributor, we kick all VCPUs to get
>> potentially pending interrupts serviced.
>>
>> This is based on Linux commit 2b0cda878965, written by Marc Zyngier.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>> Changelog v2 ... v3:
>> - fix misleading comment about PRODUCT_ID letter
>> - clarify on meaning of VARIANT_ID_XEN
>>
>> Changelog v1 ... v2:
>> use new IIDR values (KVM product ID, Xen revision)
>> - add comment on handling GICD enablement
>> - use new vcpu_kick() function
>>
>>  xen/arch/arm/vgic/vgic-mmio-v2.c | 63 +++++++++++++++++++++++++++++++++++++++-
>>  xen/arch/arm/vgic/vgic.c         | 15 ++++++++++
>>  xen/arch/arm/vgic/vgic.h         |  9 ++++++
>>  3 files changed, 86 insertions(+), 1 deletion(-)
>>
>> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> index 6f10cf16ca..43c1ab5906 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
>> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> @@ -20,9 +20,70 @@
>>  #include "vgic.h"
>>  #include "vgic-mmio.h"
>>  
>> +static unsigned long vgic_mmio_read_v2_misc(struct vcpu *vcpu,
>> +                                            paddr_t addr, unsigned int len)
>> +{
>> +    uint32_t value;
>> +
>> +    switch ( addr & 0x0c )      /* filter for the 4 registers handled here */
>> +    {
>> +    case GICD_CTLR:
>> +        value = vcpu->domain->arch.vgic.enabled ? GICD_CTL_ENABLE : 0;
>> +        break;
>> +    case GICD_TYPER:
>> +        value = vcpu->domain->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
>> +        value = (value >> 5) - 1;
>> +        value |= (vcpu->domain->max_vcpus - 1) << 5;
> 
> NIT: You can reuse GICD_TYPE_CPUS_SHIFT
> 
> 
>> +        break;
>> +    case GICD_IIDR:
>> +        value = (PRODUCT_ID_KVM << 24) |
>> +                (VARIANT_ID_XEN << 16) |
>> +                (IMPLEMENTER_ARM << 0);
>> +        break;
>> +    default:
>> +        return 0;
>> +    }
>> +
>> +    return value;
>> +}
>> +
>> +static void vgic_mmio_write_v2_misc(struct vcpu *vcpu,
>> +                                    paddr_t addr, unsigned int len,
>> +                                    unsigned long val)
>> +{
>> +    struct vgic_dist *dist = &vcpu->domain->arch.vgic;
>> +    bool enabled;
>> +
>> +    switch ( addr & 0x0c )      /* filter for the 4 registers handled here */
>> +    {
>> +    case GICD_CTLR:
>> +        domain_lock(vcpu->domain);
>> +
>> +        /*
>> +         * Store the new enabled state in our distributor structure.
>> +         * Work out whether it was disabled before and now got enabled,
>> +         * so that we signal all VCPUs to check for interrupts to be injected.
>> +         */
>> +        enabled = dist->enabled;
>> +        dist->enabled = val & GICD_CTL_ENABLE;
>> +        enabled = !enabled && dist->enabled;
>> +
>> +        domain_unlock(vcpu->domain);
>> +
>> +        if ( enabled )
>> +            vgic_kick_vcpus(vcpu->domain);
>> +
>> +        break;
>> +    case GICD_TYPER:
>> +    case GICD_IIDR:
>> +        /* read-only, writes ignored */
>> +        return;
>> +    }
>> +}
>> +
>>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>      REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
>> +        vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_IGROUPR,
>>          vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index 925cda4580..37b425a16c 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -684,6 +684,21 @@ int vgic_vcpu_pending_irq(struct vcpu *vcpu)
>>      return ret;
>>  }
>>  
>> +void vgic_kick_vcpus(struct domain *d)
>> +{
>> +    struct vcpu *vcpu;
>> +
>> +    /*
>> +     * We've injected an interrupt, time to find out who deserves
>> +     * a good kick...
>> +     */
>> +    for_each_vcpu( d, vcpu )
>> +    {
>> +        if ( vgic_vcpu_pending_irq(vcpu) )
>> +            vcpu_kick(vcpu);
>> +    }
>> +}
>> +
>>  /*
>>   * Local variables:
>>   * mode: C
>> diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h
>> index 7f221fd195..aed7e4179a 100644
>> --- a/xen/arch/arm/vgic/vgic.h
>> +++ b/xen/arch/arm/vgic/vgic.h
>> @@ -17,6 +17,14 @@
>>  #ifndef __XEN_ARM_VGIC_VGIC_H__
>>  #define __XEN_ARM_VGIC_VGIC_H__
>>  
>> +/*
>> + * We piggy-back on the already used KVM product ID,  but use a different
>> + * variant (major revision) for Xen.
>> + */
>> +#define PRODUCT_ID_KVM          0x4b        /* ASCII code K */
>> +#define VARIANT_ID_XEN          0x01
>> +#define IMPLEMENTER_ARM         0x43b
>> +
>>  #define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
>>  
>>  static inline bool irq_is_pending(struct vgic_irq *irq)
>> @@ -37,6 +45,7 @@ struct vgic_irq *vgic_get_irq(struct domain *d, struct vcpu *vcpu,
>>  void vgic_put_irq(struct domain *d, struct vgic_irq *irq);
>>  void vgic_queue_irq_unlock(struct domain *d, struct vgic_irq *irq,
>>                             unsigned long flags);
>> +void vgic_kick_vcpus(struct domain *d);
>>  
>>  static inline void vgic_get_irq_kref(struct vgic_irq *irq)
>>  {

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers
  2018-03-27 22:27   ` Stefano Stabellini
@ 2018-03-28 10:37     ` Andre Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-28 10:37 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 27/03/18 23:27, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> As this register is v2 specific, its implementation lives entirely
>> in vgic-mmio-v2.c.
>> This register allows setting the source mask of an IPI.
>>
>> This is based on Linux commit ed40213ef9b0, written by Andre Przywara.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>> ---
>>  xen/arch/arm/vgic/vgic-mmio-v2.c | 81 +++++++++++++++++++++++++++++++++++++++-
>>  1 file changed, 79 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> index 9ef80608c1..32e0f6fc33 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
>> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> @@ -181,6 +181,83 @@ static void vgic_mmio_write_target(struct vcpu *vcpu,
>>      }
>>  }
>>  
>> +static unsigned long vgic_mmio_read_sgipend(struct vcpu *vcpu,
>> +                                            paddr_t addr, unsigned int len)
>> +{
>> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
>> +    uint32_t val = 0;
>> +    unsigned int i;
>> +
>> +    ASSERT(intid < VGIC_NR_SGIS);
>> +
>> +    for ( i = 0; i < len; i++ )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
>> +
>> +        val |= (uint32_t)irq->source << (i * 8);
> 
> lock?
> one more comment

(see the answer to patch 19/39)

>> +        vgic_put_irq(vcpu->domain, irq);
>> +    }
>> +
>> +    return val;
>> +}
>> +
>> +static void vgic_mmio_write_sgipendc(struct vcpu *vcpu,
>> +                                     paddr_t addr, unsigned int len,
>> +                                     unsigned long val)
>> +{
>> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
>> +    unsigned int i;
>> +    unsigned long flags;
>> +
>> +    ASSERT(intid < VGIC_NR_SGIS);
>> +
>> +    for ( i = 0; i < len; i++ )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
>> +
>> +        spin_lock_irqsave(&irq->irq_lock, flags);
>> +
>> +        irq->source &= ~((val >> (i * 8)) & 0xff);
>> +        if ( !irq->source )
>> +            irq->pending_latch = false;
>> +
>> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
>> +        vgic_put_irq(vcpu->domain, irq);
>> +    }
>> +}
>> +
>> +static void vgic_mmio_write_sgipends(struct vcpu *vcpu,
>> +                                     paddr_t addr, unsigned int len,
>> +                                     unsigned long val)
>> +{
>> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
>> +    unsigned int i;
>> +    unsigned long flags;
>> +
>> +    ASSERT(intid < VGIC_NR_SGIS);
>> +
>> +    for ( i = 0; i < len; i++ )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
>> +
>> +        spin_lock_irqsave(&irq->irq_lock, flags);
>> +
>> +        irq->source |= (val >> (i * 8)) & 0xff;
>> +
>> +        if ( irq->source )
>> +        {
>> +            irq->pending_latch = true;
>> +            vgic_queue_irq_unlock(vcpu->domain, irq, flags);
>> +        }
>> +        else
>> +        {
>> +            spin_unlock_irqrestore(&irq->irq_lock, flags);
>> +        }
> 
> NIT: it should be safe to call vgic_queue_irq_unlock regardless, right?

I don't think vgic_queue_irq_unlock() and subsequent functions can deal
with the IRQ being pending, but not having a source bit set:
http://www.linux-arm.org/git?p=xen-ap.git;a=blob;f=xen/arch/arm/vgic/vgic-v2.c;h=6a84e741ee0a#l205

Besides, this scheme of:
	if ( needs to be injected )
	{
		make_pending();
		vgic_queue_irq_unlock();
	}
	else
	{
		spin_unlock_irqrestore();
	}

is all over the place, and I don't want to deviate from that and the KVM
implementation needlessly.

Cheers,
Andre.



>> +        vgic_put_irq(vcpu->domain, irq);
>> +    }
>> +}
>> +
>>  static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>      REGISTER_DESC_WITH_LENGTH(GICD_CTLR,
>>          vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
>> @@ -219,10 +296,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>          vgic_mmio_read_raz, vgic_mmio_write_sgir, 4,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_LENGTH(GICD_CPENDSGIR,
>> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
>> +        vgic_mmio_read_sgipend, vgic_mmio_write_sgipendc, 16,
>>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>      REGISTER_DESC_WITH_LENGTH(GICD_SPENDSGIR,
>> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 16,
>> +        vgic_mmio_read_sgipend, vgic_mmio_write_sgipends, 16,
>>          VGIC_ACCESS_32bit | VGIC_ACCESS_8bit),
>>  };
>>  
>> -- 
>> 2.14.1
>>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init
  2018-03-27 23:16   ` Stefano Stabellini
  2018-03-28  0:06     ` Stefano Stabellini
@ 2018-03-28 10:49     ` Andre Przywara
  1 sibling, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-28 10:49 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 28/03/18 00:16, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> This patch allocates and initializes the data structures used to model
>> the vgic distributor and virtual cpu interfaces. At that stage the
>> number of IRQs and number of virtual CPUs is frozen.
>> Implement the various functions that the Xen arch code is expecting to
>> call during domain and VCPU setup to initialize the VGIC.
>> Their prototypes are already in existing header files.
>>
>> This is based on Linux commit ad275b8bb1e6, written by Eric Auger.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>> Changelog v2 ... v3:
>> - move ROUNDUP(nr_spis) call before boundary check
>>
>> Changelog v1 ... v2:
>> - remove stray kvm_ prefix in comment
>> - use unsigned int
>> - ROUNDUP number of SPIs
>> - fix indentation
>>
>>  xen/arch/arm/vgic/vgic-init.c | 201 ++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 201 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
>> index d091c92ed0..bfd3d09edb 100644
>> --- a/xen/arch/arm/vgic/vgic-init.c
>> +++ b/xen/arch/arm/vgic/vgic-init.c
>> @@ -15,11 +15,83 @@
>>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>>   */
>>  
>> +#include <xen/lib.h>
>>  #include <xen/sched.h>
>>  #include <asm/new_vgic.h>
>>  
>>  #include "vgic.h"
>>  
>> +/*
>> + * Initialization rules: there are multiple stages to the vgic
>> + * initialization, both for the distributor and the CPU interfaces.  The basic
>> + * idea is that even though the VGIC is not functional or not requested from
>> + * user space, the critical path of the run loop can still call VGIC functions
>> + * that just won't do anything, without them having to check additional
>> + * initialization flags to ensure they don't look at uninitialized data
>> + * structures.
>> + *
>> + * Distributor:
>> + *
>> + * - vgic_early_init(): initialization of static data that doesn't
>> + *   depend on any sizing information or emulation type. No allocation
>> + *   is allowed there.
>> + *
>> + * - vgic_init(): allocation and initialization of the generic data
>> + *   structures that depend on sizing information (number of CPUs,
>> + *   number of interrupts). Also initializes the vcpu specific data
>> + *   structures. Can be executed lazily for GICv2.
>> + *
>> + * CPU Interface:
>> + *
>> + * - vgic_vcpu_early_init(): initialization of static data that
>> + *   doesn't depend on any sizing information or emulation type. No
>> + *   allocation is allowed there.
>> + */
>> +
>> +/**
>> + * vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
>> + * @vcpu: The VCPU whose VGIC data structures whould be initialized
>> + *
>> + * Only do initialization, but do not actually enable the VGIC CPU interface
>> + * yet.
>> + */
>> +static void vgic_vcpu_early_init(struct vcpu *vcpu)
>> +{
>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
>> +    unsigned int i;
>> +
>> +    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
>> +    spin_lock_init(&vgic_cpu->ap_list_lock);
>> +
>> +    /*
>> +     * Enable and configure all SGIs to be edge-triggered and
>> +     * configure all PPIs as level-triggered.
>> +     */
>> +    for ( i = 0; i < VGIC_NR_PRIVATE_IRQS; i++ )
>> +    {
>> +        struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
>> +
>> +        INIT_LIST_HEAD(&irq->ap_list);
>> +        spin_lock_init(&irq->irq_lock);
>> +        irq->intid = i;
>> +        irq->vcpu = NULL;
>> +        irq->target_vcpu = vcpu;
>> +        irq->targets = 1U << vcpu->vcpu_id;
>> +        atomic_set(&irq->refcount, 0);
>> +        if ( vgic_irq_is_sgi(i) )
>> +        {
>> +            /* SGIs */
>> +            irq->enabled = 1;
>> +            irq->config = VGIC_CONFIG_EDGE;
>> +        }
>> +        else
>> +        {
>> +            /* PPIs */
>> +            irq->config = VGIC_CONFIG_LEVEL;
>> +        }
>> +    }
>> +}
>> +
>>  /* CREATION */
>>  
>>  /**
>> @@ -50,6 +122,135 @@ int domain_vgic_register(struct domain *d, int *mmio_count)
>>      return 0;
>>  }
>>  
>> +/* INIT/DESTROY */
>> +
>> +/**
>> + * domain_vgic_init: initialize the dist data structures
>> + * @d: domain pointer
>> + * @nr_spis: number of SPIs
>> + */
>> +int domain_vgic_init(struct domain *d, unsigned int nr_spis)
>> +{
>> +    struct vgic_dist *dist = &d->arch.vgic;
>> +    unsigned int i;
>> +    int ret;
>> +
>> +    /* The number of SPIs must be a multiple of 32 per the GIC spec. */
>> +    nr_spis = ROUNDUP(nr_spis, 32);
>> +
>> +    /* Limit the number of virtual SPIs supported to (1020 - 32) = 988  */
>> +    if ( nr_spis > (1020 - NR_LOCAL_IRQS) )
>> +        return -EINVAL;
>> +
>> +    dist->nr_spis = nr_spis;
>> +    dist->spis = xzalloc_array(struct vgic_irq, nr_spis);
>> +    if ( !dist->spis )
>> +        return  -ENOMEM;
>> +
>> +    /*
>> +     * In the following code we do not take the irq struct lock since
>> +     * no other action on irq structs can happen while the VGIC is
>> +     * not initialized yet:
>> +     * If someone wants to inject an interrupt or does a MMIO access, we
>> +     * require prior initialization in case of a virtual GICv3 or trigger
>> +     * initialization when using a virtual GICv2.
>> +     */
>> +    for ( i = 0; i < nr_spis; i++ )
>> +    {
>> +        struct vgic_irq *irq = &dist->spis[i];
>> +
>> +        irq->intid = i + VGIC_NR_PRIVATE_IRQS;
>> +        INIT_LIST_HEAD(&irq->ap_list);
>> +        spin_lock_init(&irq->irq_lock);
>> +        irq->vcpu = NULL;
>> +        irq->target_vcpu = NULL;
>> +        atomic_set(&irq->refcount, 0);
>> +        if ( dist->version == GIC_V2 )
>> +            irq->targets = 0;
>> +        else
>> +            irq->mpidr = 0;
>> +    }
>> +
>> +    INIT_LIST_HEAD(&dist->lpi_list_head);
>> +    spin_lock_init(&dist->lpi_list_lock);
>> +
>> +    if ( dist->version == GIC_V2 )
>> +        ret = vgic_v2_map_resources(d);
>> +    else
>> +        ret = -ENXIO;
>> +
>> +    if ( ret )
>> +        return ret;
>> +
>> +    /* allocated_irqs() is used by Xen to find available vIRQs */
>> +    d->arch.vgic.allocated_irqs =
>> +        xzalloc_array(unsigned long, BITS_TO_LONGS(vgic_num_irqs(d)));
>> +    if ( !d->arch.vgic.allocated_irqs )
>> +        return -ENOMEM;
>> +
>> +    /* vIRQ0-15 (SGIs) are reserved */
>> +    for ( i = 0; i < NR_GIC_SGI; i++ )
>> +        set_bit(i, d->arch.vgic.allocated_irqs);
>> +
>> +    return 0;
>> +}
>> +
>> +/**
>> + * vcpu_vgic_init() - Register VCPU-specific KVM iodevs
>> + * was: kvm_vgic_vcpu_init()
> 
> Is this "was: kvm_vgic_vcpu_init" really helpful?

The idea for those "was: " hints is to have some grep fodder in case
someone needs to port a KVM patch. Admittedly I didn't do this
consequently enough, I think.
In this particular case please mind the subtle change from vgic_vcpu to
vcpu_vgic here ;-)

> In any case
> 
> Acked-by: Stefano Stabellini <sstabellini@kernel.org>

Thanks!
Andre.

>> + * Xen: adding vgic_vx_enable() call
>> + * @vcpu: pointer to the VCPU being created and initialized
>> + */
>> +int vcpu_vgic_init(struct vcpu *vcpu)
>> +{
>> +    int ret = 0;
>> +
>> +    vgic_vcpu_early_init(vcpu);
>> +
>> +    if ( gic_hw_version() == GIC_V2 )
>> +        vgic_v2_enable(vcpu);
>> +    else
>> +        ret = -ENXIO;
>> +
>> +    return ret;
>> +}
>> +
>> +void domain_vgic_free(struct domain *d)
>> +{
>> +    struct vgic_dist *dist = &d->arch.vgic;
>> +        int i, ret;
>> +
>> +    for ( i = 0; i < dist->nr_spis; i++ )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(d, NULL, 32 + i);
>> +
>> +        if ( !irq->hw )
>> +            continue;
>> +
>> +        ret = release_guest_irq(d, irq->hwintid);
>> +        if ( ret )
>> +            dprintk(XENLOG_G_WARNING,
>> +                    "d%u: Failed to release virq %u ret = %d\n",
>> +                    d->domain_id, 32 + i, ret);
>> +    }
>> +
>> +    dist->ready = false;
>> +    dist->initialized = false;
>> +
>> +    xfree(dist->spis);
>> +    xfree(dist->allocated_irqs);
>> +    dist->nr_spis = 0;
>> +}
>> +
>> +int vcpu_vgic_free(struct vcpu *vcpu)
>> +{
>> +    struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic;
>> +
>> +    INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
>> +
>> +    return 0;
>> +}
>> +
>>  /*
>>   * Local variables:
>>   * mode: C

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 20/39] ARM: new VGIC: Add PENDING registers handlers
  2018-03-27 21:14   ` Stefano Stabellini
@ 2018-03-28 14:10     ` Andre Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-28 14:10 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 27/03/18 22:14, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> The pending register handlers are shared between the v2 and v3
>> emulation, so their implementation goes into vgic-mmio.c, to be easily
>> referenced from the v3 emulation as well later.
>> For level triggered interrupts the real line level is unaffected by
>> this write, so we keep this state separate and combine it with the
>> device's level to get the actual pending state.
>> Hardware mapped IRQs need some special handling, as their hardware state
>> has to be coordinated with the virtual pending bit to avoid hanging
>> or masked interrupts.
>>
>> This is based on Linux commit 96b298000db4, written by Andre Przywara.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>> ---
>>  xen/arch/arm/vgic/vgic-mmio-v2.c |   4 +-
>>  xen/arch/arm/vgic/vgic-mmio.c    | 125 +++++++++++++++++++++++++++++++++++++++
>>  xen/arch/arm/vgic/vgic-mmio.h    |  11 ++++
>>  3 files changed, 138 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> index 7efd1c4eb4..a48c554040 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
>> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
>> @@ -95,10 +95,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
>>          vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
>> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> +        vgic_mmio_read_pending, vgic_mmio_write_spending, 1,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICPENDR,
>> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> +        vgic_mmio_read_pending, vgic_mmio_write_cpending, 1,
>>          VGIC_ACCESS_32bit),
>>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISACTIVER,
>>          vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
>> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
>> index f219b7c509..53b8978c02 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio.c
>> +++ b/xen/arch/arm/vgic/vgic-mmio.c
>> @@ -156,6 +156,131 @@ void vgic_mmio_write_cenable(struct vcpu *vcpu,
>>      }
>>  }
>>  
>> +unsigned long vgic_mmio_read_pending(struct vcpu *vcpu,
>> +                                     paddr_t addr, unsigned int len)
>> +{
>> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +    uint32_t value = 0;
>> +    unsigned int i;
>> +
>> +    /* Loop over all IRQs affected by this read */
>> +    for ( i = 0; i < len * 8; i++ )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
>> +
>> +        if ( irq_is_pending(irq) )
>> +            value |= (1U << i);
> 
> Same question: shouldn't we take the irq->irq_lock?
> 
> 
>> +        vgic_put_irq(vcpu->domain, irq);
>> +    }
>> +
>> +    return value;
>> +}
>> +
>> +void vgic_mmio_write_spending(struct vcpu *vcpu,
>> +                              paddr_t addr, unsigned int len,
>> +                              unsigned long val)
>> +{
>> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +    unsigned int i;
>> +    unsigned long flags;
>> +    irq_desc_t *desc;
>> +
>> +    for_each_set_bit( i, &val, len * 8 )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
>> +
>> +        spin_lock_irqsave(&irq->irq_lock, flags);
>> +        irq->pending_latch = true;
>> +
>> +        /* To observe the locking order, just take the irq_desc pointer here. */
>> +        if ( irq->hw )
>> +            desc = irq_to_desc(irq->hwintid);
>> +        else
>> +            desc = NULL;
>> +
>> +        vgic_queue_irq_unlock(vcpu->domain, irq, flags);
>> +
>> +        /*
>> +         * When the VM sets the pending state for a HW interrupt on the virtual
>> +         * distributor we set the active state on the physical distributor,
>> +         * because the virtual interrupt can become active and then the guest
>> +         * can deactivate it.
>> +         */
>> +        if ( desc )
>> +        {
>> +            spin_lock_irqsave(&desc->lock, flags);
>> +            spin_lock(&irq->irq_lock);
>> +
>> +            /* This h/w IRQ should still be assigned to the virtual IRQ. */
>> +            ASSERT(irq->hw && desc->irq == irq->hwintid);
>> +
>> +            gic_set_active_state(desc, true);
>> +
>> +            spin_unlock(&irq->irq_lock);
>> +            spin_unlock_irqrestore(&desc->lock, flags);
>> +        }
>> +
>> +        vgic_put_irq(vcpu->domain, irq);
>> +    }
>> +}
>> +
>> +void vgic_mmio_write_cpending(struct vcpu *vcpu,
>> +                              paddr_t addr, unsigned int len,
>> +                              unsigned long val)
>> +{
>> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
>> +    unsigned int i;
>> +    unsigned long flags;
>> +    irq_desc_t *desc;
>> +
>> +    for_each_set_bit( i, &val, len * 8 )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
>> +
>> +        spin_lock_irqsave(&irq->irq_lock, flags);
>> +        irq->pending_latch = false;
>> +
>> +        /* To observe the locking order, just take the irq_desc pointer here. */
>> +        if ( irq->hw )
>> +            desc = irq_to_desc(irq->hwintid);
>> +        else
>> +            desc = NULL;
>> +
>> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
>> +
>> +        /*
>> +         * We don't want the guest to effectively mask the physical
>> +         * interrupt by doing a write to SPENDR followed by a write to
>> +         * CPENDR for HW interrupts, so we clear the active state on
>> +         * the physical side if the virtual interrupt is not active.
>> +         * This may lead to taking an additional interrupt on the
>> +         * host, but that should not be a problem as the worst that
>> +         * can happen is an additional vgic injection.  We also clear
>> +         * the pending state to maintain proper semantics for edge HW
>> +         * interrupts.
>> +         */
>> +        if ( desc )
>> +        {
>> +            spin_lock_irqsave(&desc->lock, flags);
>> +            spin_lock(&irq->irq_lock);
>> +
>> +            /* This h/w IRQ should still be assigned to the virtual IRQ. */
>> +            ASSERT(irq->hw && desc->irq == irq->hwintid);
>> +
>> +            gic_set_pending_state(desc, false);
> 
> Should we check irq_is_pending before calling gic_set_pending_state?
> I am asking because I think it is possible to race against another
> concurrent change that could come in after releasing irq_lock and before
> taking desc->lock and irq->irq_lock again. If we check what's the latest
> about the pending state we should be safe against the race, similarly to
> what you did in the previous patch in vgic_sync_hardware_irq.

Yeah, that's a good point, that belongs to the condition of "nothing
(critical) has changed meanwhile".

Cheers,
Andre.

>> +            if (!irq->active)
>> +                gic_set_active_state(desc, false);
>> +
>> +            spin_unlock(&irq->irq_lock);
>> +            spin_unlock_irqrestore(&desc->lock, flags);
>> +        }
>> +
>> +
>> +        vgic_put_irq(vcpu->domain, irq);
>> +    }
>> +}
>> +
>>  static int match_region(const void *key, const void *elt)
>>  {
>>      const unsigned int offset = (unsigned long)key;
>> diff --git a/xen/arch/arm/vgic/vgic-mmio.h b/xen/arch/arm/vgic/vgic-mmio.h
>> index a2cebd77f4..5c927f28b0 100644
>> --- a/xen/arch/arm/vgic/vgic-mmio.h
>> +++ b/xen/arch/arm/vgic/vgic-mmio.h
>> @@ -97,6 +97,17 @@ void vgic_mmio_write_cenable(struct vcpu *vcpu,
>>                               paddr_t addr, unsigned int len,
>>                               unsigned long val);
>>  
>> +unsigned long vgic_mmio_read_pending(struct vcpu *vcpu,
>> +                                     paddr_t addr, unsigned int len);
>> +
>> +void vgic_mmio_write_spending(struct vcpu *vcpu,
>> +                              paddr_t addr, unsigned int len,
>> +                              unsigned long val);
>> +
>> +void vgic_mmio_write_cpending(struct vcpu *vcpu,
>> +                              paddr_t addr, unsigned int len,
>> +                              unsigned long val);
>> +
>>  unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev);
>>  
>>  #endif
>> -- 
>> 2.14.1
>>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-28  0:01   ` Stefano Stabellini
@ 2018-03-28 15:39     ` Andre Przywara
  2018-03-28 17:46       ` Stefano Stabellini
  2018-04-03 13:34     ` Julien Grall
  1 sibling, 1 reply; 122+ messages in thread
From: Andre Przywara @ 2018-03-28 15:39 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 28/03/18 01:01, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> The event channel IRQ has level triggered semantics, however the current
>> VGIC treats everything as edge triggered.
>> To correctly process those IRQs, we have to lower the (virtual) IRQ line
>> at some point in time, depending on whether ther interrupt condition
>> still prevails.
>> Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
>> line match its status, and call this function upon every hypervisor
>> entry.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>> ---
>>  xen/arch/arm/domain.c       | 7 +++++++
>>  xen/arch/arm/traps.c        | 1 +
>>  xen/include/asm-arm/event.h | 1 +
>>  3 files changed, 9 insertions(+)
>>
>> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
>> index ff97f2bc76..9688e62f78 100644
>> --- a/xen/arch/arm/domain.c
>> +++ b/xen/arch/arm/domain.c
>> @@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
>>      vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
>>  }
>>  
>> +void vcpu_update_evtchn_irq(struct vcpu *v)
>> +{
>> +    bool pending = vcpu_info(v, evtchn_upcall_pending);
>> +
>> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
>> +}
>> +
>>  /* The ARM spec declares that even if local irqs are masked in
>>   * the CPSR register, an irq should wake up a cpu from WFI anyway.
>>   * For this reason we need to check for irqs that need delivery,
>> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
>> index 2638446693..5c18e918b0 100644
>> --- a/xen/arch/arm/traps.c
>> +++ b/xen/arch/arm/traps.c
>> @@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
>>           * trap and how it can be optimised.
>>           */
>>          vtimer_update_irqs(current);
>> +        vcpu_update_evtchn_irq(current);
>>  #endif
> 
> I am replying to this patch, even though I have already committed it, to
> point out a problem with the way we currently handle the evtchn_irq in
> this series.
> 
> The short version is that I think we should configure the PPI
> corresponding to the evtchn_irq as EDGE instead of LEVEL.

Well, that's really a separate problem, then. We can't just configure
the PPI at will, it has to match the device semantic.
When writing this patch, I checked how the the evtchn "device" is
implemented, and it screams "level IRQ" to me:
- We have a flag (evtchn_upcall_pending), which stores the current
interrupt state.
- This flag gets set by the producer when the interrupt condition is true.
- It gets cleared by the *consumer* once it has handled the request.

So if the event channel mechanism should be edge (which would be fair
enough), we need to change the code to implement this: the interrupt
condition should be cleared once we *injected* the IRQ - and not only
when the consumer has signalled completion.

Another thing to consider: by the spec the *configurability* of PPIs is
implementation defined. The KVM implementation chose to fix all of them
to "level", which we need for the arch timer. So setting the evtchn PPI
to edge would be ignored. We could deviate from that, but I need to
check what the side effects are.

> The long explanation follows, please correct me if I am wrong.
> 
> 1) vcpuA/cpuA is running, it has already handled the event, cleared
> evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> Xen yet. It is still in guest mode.
> 
> 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> vgic_inject_irq. However, because irq->line_level is high, it is not
> injected.

So this is a case where we fail to sync in time on the actual emulated
line level. KVM recently gained some nice code to solve this: We can
register per-IRQ functions that return the line level. For hardware
mapped IRQs this queries the distributor, but for the arch timer for
instance it just uses a shortcut to read CNTV_CTL_EL0.
The evtchn IRQ could just check evtchn_upcall_pending.

I can take a look at a follow up patch to implement this.

Cheers,
Andre.


> 3) vcpuA has to wait until trapping into Xen, calling
> vcpu_update_evtchn_irq, and going back to guest mode before receiving
> the event. This is theoretically a very long time.
> 
> 
> Instead what should happen is:
> 
> 1) vcpuA/cpuA is running, it has already handled the event, cleared
> evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> Xen yet. It is still in guest mode.
> 
> 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> vgic_inject_irq, which calls vgic_queue_irq_unlock that
> vcpu_kick(vcpuA), forcing it to take the event immediately.
> 
> Am I right? Wouldn't it be safer to continue configuring the evtchn_irq
> as edge even in the new vgic?
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers
  2018-03-28  9:09     ` Andre Przywara
@ 2018-03-28 17:19       ` Stefano Stabellini
  0 siblings, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-28 17:19 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 28 Mar 2018, Andre Przywara wrote:
> Hi,
> 
> On 27/03/18 22:06, Stefano Stabellini wrote:
> > On Wed, 21 Mar 2018, Andre Przywara wrote:
> >> As the enable register handlers are shared between the v2 and v3
> >> emulation, their implementation goes into vgic-mmio.c, to be easily
> >> referenced from the v3 emulation as well later.
> >> This introduces a vgic_sync_hardware_irq() function, which updates the
> >> physical side of a hardware mapped virtual IRQ.
> >> Because the existing locking order between vgic_irq->irq_lock and
> >> irq_desc->lock dictates so, we drop the irq_lock and retake them in the
> >> proper order.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> >> Reviewed-by: Julien Grall <julien.grall@arm.com>
> >> ---
> >> Changelog v2 ... v3:
> >> - fix indentation
> >> - fix wording in comment
> >> - add Reviewed-by:
> >>
> >> Changelog v1 ... v2:
> >> - ASSERT on h/w IRQ and vIRQ staying in sync
> >>
> >>  xen/arch/arm/vgic/vgic-mmio-v2.c |   4 +-
> >>  xen/arch/arm/vgic/vgic-mmio.c    | 117 +++++++++++++++++++++++++++++++++++++++
> >>  xen/arch/arm/vgic/vgic-mmio.h    |  11 ++++
> >>  xen/arch/arm/vgic/vgic.c         |  40 +++++++++++++
> >>  xen/arch/arm/vgic/vgic.h         |   3 +
> >>  5 files changed, 173 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/xen/arch/arm/vgic/vgic-mmio-v2.c b/xen/arch/arm/vgic/vgic-mmio-v2.c
> >> index 43c1ab5906..7efd1c4eb4 100644
> >> --- a/xen/arch/arm/vgic/vgic-mmio-v2.c
> >> +++ b/xen/arch/arm/vgic/vgic-mmio-v2.c
> >> @@ -89,10 +89,10 @@ static const struct vgic_register_region vgic_v2_dist_registers[] = {
> >>          vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
> >>          VGIC_ACCESS_32bit),
> >>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISENABLER,
> >> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> >> +        vgic_mmio_read_enable, vgic_mmio_write_senable, 1,
> >>          VGIC_ACCESS_32bit),
> >>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ICENABLER,
> >> -        vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> >> +        vgic_mmio_read_enable, vgic_mmio_write_cenable, 1,
> >>          VGIC_ACCESS_32bit),
> >>      REGISTER_DESC_WITH_BITS_PER_IRQ(GICD_ISPENDR,
> >>          vgic_mmio_read_raz, vgic_mmio_write_wi, 1,
> >> diff --git a/xen/arch/arm/vgic/vgic-mmio.c b/xen/arch/arm/vgic/vgic-mmio.c
> >> index a03e8d88b9..f219b7c509 100644
> >> --- a/xen/arch/arm/vgic/vgic-mmio.c
> >> +++ b/xen/arch/arm/vgic/vgic-mmio.c
> >> @@ -39,6 +39,123 @@ void vgic_mmio_write_wi(struct vcpu *vcpu, paddr_t addr,
> >>      /* Ignore */
> >>  }
> >>  
> >> +/*
> >> + * Read accesses to both GICD_ICENABLER and GICD_ISENABLER return the value
> >> + * of the enabled bit, so there is only one function for both here.
> >> + */
> >> +unsigned long vgic_mmio_read_enable(struct vcpu *vcpu,
> >> +                                    paddr_t addr, unsigned int len)
> >> +{
> >> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 1);
> >> +    uint32_t value = 0;
> >> +    unsigned int i;
> >> +
> >> +    /* Loop over all IRQs affected by this read */
> >> +    for ( i = 0; i < len * 8; i++ )
> >> +    {
> >> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> >> +
> >> +        if ( irq->enabled )
> >> +            value |= (1U << i);
> > 
> > Don't we need to take the irq->irq_lock before reading irq->enabled?
> 
> Not really. A boolean has no illegal state, so we can't read any
> intermediate values.
> 
> If you think about concurrent writes: That is even racy on real
> hardware, and normally you expect a sane driver to take a lock around
> every distributor access (cf. spin_lock(&gicv2.lock)).
> Keep in mind that only a guest can change the enabled state.
> 
> So the rationale behind those unlocked reads is:
> As long as it doesn't harm the hypervisor, we don't care too much about
> being 100% correct in a situation that is out of spec anyway.
> We discussed this issue also with Julien before:
> https://lists.xen.org/archives/html/xen-devel/2018-02/msg02148.html

OK, I buy the argument.

Acked-by: Stefano Stabellini <sstabellini@kernel.org>

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers
  2018-03-28 10:36     ` Andre Przywara
@ 2018-03-28 17:20       ` Stefano Stabellini
  2018-03-28 17:22       ` [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-28 17:20 UTC (permalink / raw)
  To: Andre Przywara; +Cc: marc.zyngier, xen-devel, Julien Grall, Stefano Stabellini

On Wed, 28 Mar 2018, Andre Przywara wrote:
> On 27/03/18 21:38, Stefano Stabellini wrote:
> > On Wed, 21 Mar 2018, Andre Przywara wrote:
> >> Those three registers are v2 emulation specific, so their implementation
> >> lives entirely in vgic-mmio-v2.c. Also they are handled in one function,
> >> as their implementation is pretty simple.
> >> We choose to piggy-back on the existing KVM identification registers,
> >> but use a different variant (major revision).
> > 
> > CC'ing Marc.
> > 
> > Reusing the KVM product ID could cause issues, for instance we could
> > clash with KVM if Linux changes the Major number. If we were to actually
> > reuse KVM's PRODUCT_ID we would need a better coordination in place.
> 
> Marc is aware of this, as this approach was decided after a brief
> discussion with Julien and him last week.
> If we need a quirk on the (guest) GIC driver side for the KVM VGIC, KVM
> would bump the revision number, not the variant.
> This is a good as coordination can realistically ever get.

Sure, as long as it gets documented. It needs to be written down
somewhere and committed.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers
  2018-03-28 10:36     ` Andre Przywara
  2018-03-28 17:20       ` Stefano Stabellini
@ 2018-03-28 17:22       ` Stefano Stabellini
  1 sibling, 0 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-28 17:22 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 28 Mar 2018, Andre Przywara wrote:
> >> +static void vgic_mmio_write_sgipends(struct vcpu *vcpu,
> >> +                                     paddr_t addr, unsigned int len,
> >> +                                     unsigned long val)
> >> +{
> >> +    uint32_t intid = VGIC_ADDR_TO_INTID(addr, 8);
> >> +    unsigned int i;
> >> +    unsigned long flags;
> >> +
> >> +    ASSERT(intid < VGIC_NR_SGIS);
> >> +
> >> +    for ( i = 0; i < len; i++ )
> >> +    {
> >> +        struct vgic_irq *irq = vgic_get_irq(vcpu->domain, vcpu, intid + i);
> >> +
> >> +        spin_lock_irqsave(&irq->irq_lock, flags);
> >> +
> >> +        irq->source |= (val >> (i * 8)) & 0xff;
> >> +
> >> +        if ( irq->source )
> >> +        {
> >> +            irq->pending_latch = true;
> >> +            vgic_queue_irq_unlock(vcpu->domain, irq, flags);
> >> +        }
> >> +        else
> >> +        {
> >> +            spin_unlock_irqrestore(&irq->irq_lock, flags);
> >> +        }
> > 
> > NIT: it should be safe to call vgic_queue_irq_unlock regardless, right?
> 
> I don't think vgic_queue_irq_unlock() and subsequent functions can deal
> with the IRQ being pending, but not having a source bit set:
> http://www.linux-arm.org/git?p=xen-ap.git;a=blob;f=xen/arch/arm/vgic/vgic-v2.c;h=6a84e741ee0a#l205
> 
> Besides, this scheme of:
> 	if ( needs to be injected )
> 	{
> 		make_pending();
> 		vgic_queue_irq_unlock();
> 	}
> 	else
> 	{
> 		spin_unlock_irqrestore();
> 	}
> 
> is all over the place, and I don't want to deviate from that and the KVM
> implementation needlessly.

OK

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-28 15:39     ` Andre Przywara
@ 2018-03-28 17:46       ` Stefano Stabellini
  2018-03-29  0:34         ` Julien Grall
  2018-03-29 13:44         ` Andre Przywara
  0 siblings, 2 replies; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-28 17:46 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 28 Mar 2018, Andre Przywara wrote:
> On 28/03/18 01:01, Stefano Stabellini wrote:
> > On Wed, 21 Mar 2018, Andre Przywara wrote:
> >> The event channel IRQ has level triggered semantics, however the current
> >> VGIC treats everything as edge triggered.
> >> To correctly process those IRQs, we have to lower the (virtual) IRQ line
> >> at some point in time, depending on whether ther interrupt condition
> >> still prevails.
> >> Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
> >> line match its status, and call this function upon every hypervisor
> >> entry.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> >> Reviewed-by: Julien Grall <julien.grall@arm.com>
> >> ---
> >>  xen/arch/arm/domain.c       | 7 +++++++
> >>  xen/arch/arm/traps.c        | 1 +
> >>  xen/include/asm-arm/event.h | 1 +
> >>  3 files changed, 9 insertions(+)
> >>
> >> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> >> index ff97f2bc76..9688e62f78 100644
> >> --- a/xen/arch/arm/domain.c
> >> +++ b/xen/arch/arm/domain.c
> >> @@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
> >>      vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
> >>  }
> >>  
> >> +void vcpu_update_evtchn_irq(struct vcpu *v)
> >> +{
> >> +    bool pending = vcpu_info(v, evtchn_upcall_pending);
> >> +
> >> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
> >> +}
> >> +
> >>  /* The ARM spec declares that even if local irqs are masked in
> >>   * the CPSR register, an irq should wake up a cpu from WFI anyway.
> >>   * For this reason we need to check for irqs that need delivery,
> >> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> >> index 2638446693..5c18e918b0 100644
> >> --- a/xen/arch/arm/traps.c
> >> +++ b/xen/arch/arm/traps.c
> >> @@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
> >>           * trap and how it can be optimised.
> >>           */
> >>          vtimer_update_irqs(current);
> >> +        vcpu_update_evtchn_irq(current);
> >>  #endif
> > 
> > I am replying to this patch, even though I have already committed it, to
> > point out a problem with the way we currently handle the evtchn_irq in
> > this series.
> > 
> > The short version is that I think we should configure the PPI
> > corresponding to the evtchn_irq as EDGE instead of LEVEL.
> 
> Well, that's really a separate problem, then. We can't just configure
> the PPI at will, it has to match the device semantic.
> When writing this patch, I checked how the the evtchn "device" is
> implemented, and it screams "level IRQ" to me:
> - We have a flag (evtchn_upcall_pending), which stores the current
> interrupt state.
> - This flag gets set by the producer when the interrupt condition is true.
> - It gets cleared by the *consumer* once it has handled the request.
> 
> So if the event channel mechanism should be edge (which would be fair
> enough), we need to change the code to implement this: the interrupt
> condition should be cleared once we *injected* the IRQ - and not only
> when the consumer has signalled completion.
> 
> Another thing to consider: by the spec the *configurability* of PPIs is
> implementation defined. The KVM implementation chose to fix all of them
> to "level", which we need for the arch timer. So setting the evtchn PPI
> to edge would be ignored. We could deviate from that, but I need to
> check what the side effects are.
> 
> > The long explanation follows, please correct me if I am wrong.
> > 
> > 1) vcpuA/cpuA is running, it has already handled the event, cleared
> > evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> > Xen yet. It is still in guest mode.
> > 
> > 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> > vgic_inject_irq. However, because irq->line_level is high, it is not
> > injected.
> 
> So this is a case where we fail to sync in time on the actual emulated
> line level. KVM recently gained some nice code to solve this: We can
> register per-IRQ functions that return the line level. For hardware
> mapped IRQs this queries the distributor, but for the arch timer for
> instance it just uses a shortcut to read CNTV_CTL_EL0.
> The evtchn IRQ could just check evtchn_upcall_pending.
> 
> I can take a look at a follow up patch to implement this.

I agree that the evtchn_upcall_pending mechanism is very similar to a
level interrupt, however the mechanism to bring the notification to the
guest is edge, even on x86. Even with the new vgic implementation it
falls very naturally in the edge pattern of behaviors. This is one of
those cases where I would be happy to deviate from the KVM
implementation, because it makes sense and would be easier to maintain
going forward. We can even get rid of vcpu_update_evtchn_irq.

I am OK with a not-ideal short term fix by the end of this week, as long
as we come up with a proper fix later, by the release date. But in this
instance, wouldn't be enough to change the PPI type to EDGE, remove
vcpu_update_evtchn_irq, and be done with it?



> > 3) vcpuA has to wait until trapping into Xen, calling
> > vcpu_update_evtchn_irq, and going back to guest mode before receiving
> > the event. This is theoretically a very long time.
> > 
> > 
> > Instead what should happen is:
> > 
> > 1) vcpuA/cpuA is running, it has already handled the event, cleared
> > evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> > Xen yet. It is still in guest mode.
> > 
> > 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> > vgic_inject_irq, which calls vgic_queue_irq_unlock that
> > vcpu_kick(vcpuA), forcing it to take the event immediately.
> > 
> > Am I right? Wouldn't it be safer to continue configuring the evtchn_irq
> > as edge even in the new vgic?


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs()
  2018-03-21 16:32 ` [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs() Andre Przywara
  2018-03-26 23:46   ` Stefano Stabellini
@ 2018-03-28 18:47   ` Stefano Stabellini
  2018-03-29 14:57     ` Andre Przywara
  1 sibling, 1 reply; 122+ messages in thread
From: Stefano Stabellini @ 2018-03-28 18:47 UTC (permalink / raw)
  To: Andre Przywara; +Cc: xen-devel, Julien Grall, Stefano Stabellini

On Wed, 21 Mar 2018, Andre Przywara wrote:
> When a VCPU moves to another CPU, we need to adjust the target affinity
> of any hardware mapped vIRQs, to observe our "physical-follows-virtual"
> policy.
> Implement arch_move_irqs() to adjust the physical affinity of all hardware
> mapped vIRQs targetting this VCPU.
> 
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> Reviewed-by: Julien Grall <julien.grall@arm.com>
> ---
>  xen/arch/arm/vgic/vgic.c | 39 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 39 insertions(+)
> 
> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
> index ffab0b2635..23b8abfc5e 100644
> --- a/xen/arch/arm/vgic/vgic.c
> +++ b/xen/arch/arm/vgic/vgic.c
> @@ -791,6 +791,45 @@ void gic_dump_vgic_info(struct vcpu *v)
>      spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
>  }
>  
> +/**
> + * arch_move_irqs() - migrate the physical affinity of hardware mapped vIRQs
> + * @v:  the vCPU, already assigned to the new pCPU
> + *
> + * arch_move_irqs() updates the physical affinity of all virtual IRQs
> + * targetting this given vCPU. This only affects hardware mapped IRQs. The
> + * new pCPU to target is already set in v->processor.
> + * This is called by the core code after a vCPU has been migrated to a new
> + * physical CPU.
> + */
> +void arch_move_irqs(struct vcpu *v)
> +{
> +    struct domain *d = v->domain;
> +    unsigned int i;
> +
> +    /* We only target SPIs with this function */
> +    for ( i = 0; i < d->arch.vgic.nr_spis; i++ )
> +    {
> +        struct vgic_irq *irq = vgic_get_irq(d, NULL, i + VGIC_NR_PRIVATE_IRQS);
> +        unsigned long flags;
> +
> +        if ( !irq )
> +            continue;
> +
> +        spin_lock_irqsave(&irq->irq_lock, flags);
> +
> +        /* only vIRQs that are not on a vCPU yet , but targetting this vCPU */
> +        if ( irq->hw && !irq->vcpu && irq->target_vcpu == v)
> +        {

In vgic_mmio_write_target, we change the physical irq affinity
immediately, without checking for !irq->vcpu.

I think it is OK because if a second interrupt for vcpuB comes in cpuB
while it is still injected in vcpuA/cpuA, vgic_get_irq returns the same
vgic_irq instance, vgic_inject_irq sets pending_latch to true.
vgic_queue_irq_unlock does nothing because irq->vcpu is set. Then when
vcpuA traps into Xen, vgic_prune_ap_list will take care of moving the
vgic_irq to the ap_list belonging to vcpuB.

This seems to work, but don't we also need a vcpu_kick at the end of
vgic_prune_ap_list to make sure the changes take effect in vcpuB? vcpuB
could take an very long time to trap back into Xen again.


But the real question is: why do we need to check for !irq->vcpu here?
And worse: if an interrupt has irq->vcpu set, then who will take care of
fixing the physical irq affinity later?

It looks like we should remove the "&& !irq->vcpu" here so that we can
rely on the same mechanism already in place for ITARGETSR changes.
However, would that work with already active interrupts? I think it
should but I wanted to double check.


> +            irq_desc_t *desc = irq_to_desc(irq->hwintid);
> +
> +            irq_set_affinity(desc, cpumask_of(v->processor));
> +        }
> +
> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
> +        vgic_put_irq(d, irq);
> +    }
> +}
> +
>  struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>                                        unsigned int virq)
>  {

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-28 17:46       ` Stefano Stabellini
@ 2018-03-29  0:34         ` Julien Grall
  2018-03-29 13:44         ` Andre Przywara
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-03-29  0:34 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: Andre Przywara, Julien Grall, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 6620 bytes --]

(sorry for the formatting)

On Thu, 29 Mar 2018, 01:48 Stefano Stabellini, <sstabellini@kernel.org>
wrote:

> On Wed, 28 Mar 2018, Andre Przywara wrote:
> > On 28/03/18 01:01, Stefano Stabellini wrote:
> > > On Wed, 21 Mar 2018, Andre Przywara wrote:
> > >> The event channel IRQ has level triggered semantics, however the
> current
> > >> VGIC treats everything as edge triggered.
> > >> To correctly process those IRQs, we have to lower the (virtual) IRQ
> line
> > >> at some point in time, depending on whether ther interrupt condition
> > >> still prevails.
> > >> Check the per-VCPU evtchn_upcall_pending variable to make the
> interrupt
> > >> line match its status, and call this function upon every hypervisor
> > >> entry.
> > >>
> > >> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> > >> Reviewed-by: Julien Grall <julien.grall@arm.com>
> > >> ---
> > >>  xen/arch/arm/domain.c       | 7 +++++++
> > >>  xen/arch/arm/traps.c        | 1 +
> > >>  xen/include/asm-arm/event.h | 1 +
> > >>  3 files changed, 9 insertions(+)
> > >>
> > >> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> > >> index ff97f2bc76..9688e62f78 100644
> > >> --- a/xen/arch/arm/domain.c
> > >> +++ b/xen/arch/arm/domain.c
> > >> @@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
> > >>      vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
> > >>  }
> > >>
> > >> +void vcpu_update_evtchn_irq(struct vcpu *v)
> > >> +{
> > >> +    bool pending = vcpu_info(v, evtchn_upcall_pending);
> > >> +
> > >> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq,
> pending);
> > >> +}
> > >> +
> > >>  /* The ARM spec declares that even if local irqs are masked in
> > >>   * the CPSR register, an irq should wake up a cpu from WFI anyway.
> > >>   * For this reason we need to check for irqs that need delivery,
> > >> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> > >> index 2638446693..5c18e918b0 100644
> > >> --- a/xen/arch/arm/traps.c
> > >> +++ b/xen/arch/arm/traps.c
> > >> @@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct
> cpu_user_regs *regs)
> > >>           * trap and how it can be optimised.
> > >>           */
> > >>          vtimer_update_irqs(current);
> > >> +        vcpu_update_evtchn_irq(current);
> > >>  #endif
> > >
> > > I am replying to this patch, even though I have already committed it,
> to
> > > point out a problem with the way we currently handle the evtchn_irq in
> > > this series.
> > >
> > > The short version is that I think we should configure the PPI
> > > corresponding to the evtchn_irq as EDGE instead of LEVEL.
> >
> > Well, that's really a separate problem, then. We can't just configure
> > the PPI at will, it has to match the device semantic.
> > When writing this patch, I checked how the the evtchn "device" is
> > implemented, and it screams "level IRQ" to me:
> > - We have a flag (evtchn_upcall_pending), which stores the current
> > interrupt state.
> > - This flag gets set by the producer when the interrupt condition is
> true.
> > - It gets cleared by the *consumer* once it has handled the request.
> >
> > So if the event channel mechanism should be edge (which would be fair
> > enough), we need to change the code to implement this: the interrupt
> > condition should be cleared once we *injected* the IRQ - and not only
> > when the consumer has signalled completion.
> >
> > Another thing to consider: by the spec the *configurability* of PPIs is
> > implementation defined. The KVM implementation chose to fix all of them
> > to "level", which we need for the arch timer. So setting the evtchn PPI
> > to edge would be ignored. We could deviate from that, but I need to
> > check what the side effects are.
> >
> > > The long explanation follows, please correct me if I am wrong.
> > >
> > > 1) vcpuA/cpuA is running, it has already handled the event, cleared
> > > evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> > > Xen yet. It is still in guest mode.
> > >
> > > 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> > > vgic_inject_irq. However, because irq->line_level is high, it is not
> > > injected.
> >
> > So this is a case where we fail to sync in time on the actual emulated
> > line level. KVM recently gained some nice code to solve this: We can
> > register per-IRQ functions that return the line level. For hardware
> > mapped IRQs this queries the distributor, but for the arch timer for
> > instance it just uses a shortcut to read CNTV_CTL_EL0.
> > The evtchn IRQ could just check evtchn_upcall_pending.
> >
> > I can take a look at a follow up patch to implement this.
>
> I agree that the evtchn_upcall_pending mechanism is very similar to a
> level interrupt, however the mechanism to bring the notification to the
> guest is edge, even on x86. Even with the new vgic implementation it
> falls very naturally in the edge pattern of behaviors. This is one of
> those cases where I would be happy to deviate from the KVM
> implementation, because it makes sense and would be easier to maintain
> going forward. We can even get rid of vcpu_update_evtchn_irq.
>
> I am OK with a not-ideal short term fix by the end of this week, as long
> as we come up with a proper fix later, by the release date. But in this
> instance, wouldn't be enough to change the PPI type to EDGE, remove
> vcpu_update_evtchn_irq, and be done with it?
>

We expose the event channsl as level in the DT and HVM_PARAM_CALLBACK_IRQ.
So they at least need to change.

But I an bit concerned to change those values between the 2 versions of the
vGIC.

What was the rationale to expose them as level in the old vGIC?



>
>
> > > 3) vcpuA has to wait until trapping into Xen, calling
> > > vcpu_update_evtchn_irq, and going back to guest mode before receiving
> > > the event. This is theoretically a very long time.
> > >
> > >
> > > Instead what should happen is:
> > >
> > > 1) vcpuA/cpuA is running, it has already handled the event, cleared
> > > evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> > > Xen yet. It is still in guest mode.
> > >
> > > 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> > > vgic_inject_irq, which calls vgic_queue_irq_unlock that
> > > vcpu_kick(vcpuA), forcing it to take the event immediately.
> > >
> > > Am I right? Wouldn't it be safer to continue configuring the evtchn_irq
> > > as edge even in the new vgic?
>
>
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xenproject.org
> https://lists.xenproject.org/mailman/listinfo/xen-devel

[-- Attachment #1.2: Type: text/html, Size: 8606 bytes --]

[-- Attachment #2: Type: text/plain, Size: 157 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-28 17:46       ` Stefano Stabellini
  2018-03-29  0:34         ` Julien Grall
@ 2018-03-29 13:44         ` Andre Przywara
  1 sibling, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-29 13:44 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 28/03/18 18:46, Stefano Stabellini wrote:
> On Wed, 28 Mar 2018, Andre Przywara wrote:
>> On 28/03/18 01:01, Stefano Stabellini wrote:
>>> On Wed, 21 Mar 2018, Andre Przywara wrote:
>>>> The event channel IRQ has level triggered semantics, however the current
>>>> VGIC treats everything as edge triggered.
>>>> To correctly process those IRQs, we have to lower the (virtual) IRQ line
>>>> at some point in time, depending on whether ther interrupt condition
>>>> still prevails.
>>>> Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
>>>> line match its status, and call this function upon every hypervisor
>>>> entry.
>>>>
>>>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>>>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>>>> ---
>>>>  xen/arch/arm/domain.c       | 7 +++++++
>>>>  xen/arch/arm/traps.c        | 1 +
>>>>  xen/include/asm-arm/event.h | 1 +
>>>>  3 files changed, 9 insertions(+)
>>>>
>>>> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
>>>> index ff97f2bc76..9688e62f78 100644
>>>> --- a/xen/arch/arm/domain.c
>>>> +++ b/xen/arch/arm/domain.c
>>>> @@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
>>>>      vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
>>>>  }
>>>>  
>>>> +void vcpu_update_evtchn_irq(struct vcpu *v)
>>>> +{
>>>> +    bool pending = vcpu_info(v, evtchn_upcall_pending);
>>>> +
>>>> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
>>>> +}
>>>> +
>>>>  /* The ARM spec declares that even if local irqs are masked in
>>>>   * the CPSR register, an irq should wake up a cpu from WFI anyway.
>>>>   * For this reason we need to check for irqs that need delivery,
>>>> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
>>>> index 2638446693..5c18e918b0 100644
>>>> --- a/xen/arch/arm/traps.c
>>>> +++ b/xen/arch/arm/traps.c
>>>> @@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
>>>>           * trap and how it can be optimised.
>>>>           */
>>>>          vtimer_update_irqs(current);
>>>> +        vcpu_update_evtchn_irq(current);
>>>>  #endif
>>>
>>> I am replying to this patch, even though I have already committed it, to
>>> point out a problem with the way we currently handle the evtchn_irq in
>>> this series.
>>>
>>> The short version is that I think we should configure the PPI
>>> corresponding to the evtchn_irq as EDGE instead of LEVEL.
>>
>> Well, that's really a separate problem, then. We can't just configure
>> the PPI at will, it has to match the device semantic.
>> When writing this patch, I checked how the the evtchn "device" is
>> implemented, and it screams "level IRQ" to me:
>> - We have a flag (evtchn_upcall_pending), which stores the current
>> interrupt state.
>> - This flag gets set by the producer when the interrupt condition is true.
>> - It gets cleared by the *consumer* once it has handled the request.
>>
>> So if the event channel mechanism should be edge (which would be fair
>> enough), we need to change the code to implement this: the interrupt
>> condition should be cleared once we *injected* the IRQ - and not only
>> when the consumer has signalled completion.
>>
>> Another thing to consider: by the spec the *configurability* of PPIs is
>> implementation defined. The KVM implementation chose to fix all of them
>> to "level", which we need for the arch timer. So setting the evtchn PPI
>> to edge would be ignored. We could deviate from that, but I need to
>> check what the side effects are.
>>
>>> The long explanation follows, please correct me if I am wrong.
>>>
>>> 1) vcpuA/cpuA is running, it has already handled the event, cleared
>>> evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
>>> Xen yet. It is still in guest mode.
>>>
>>> 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
>>> vgic_inject_irq. However, because irq->line_level is high, it is not
>>> injected.

I was just wondering if we could do something similar to the SBSA UART
change, where we amend vcpu_mark_events_pending() to update the line
level in the VGIC via vgic_inject_irq().

>> So this is a case where we fail to sync in time on the actual emulated
>> line level.

So to explain this:
The virtual line level is not in sync all of the time, as we don't get
signalled when the flag is cleared by the domain. We need to sync this
whenever needed, which, for once, is when the domain returns to the
hypervisor. Another point is this vcpu_mark_events_pending() here,
because we need to know the state. And fortunately we just queried it
also. So I will include a change which updates this into the new VGIC.

 KVM recently gained some nice code to solve this: We can
>> register per-IRQ functions that return the line level. For hardware
>> mapped IRQs this queries the distributor, but for the arch timer for
>> instance it just uses a shortcut to read CNTV_CTL_EL0.
>> The evtchn IRQ could just check evtchn_upcall_pending.
>>
>> I can take a look at a follow up patch to implement this.
> 
> I agree that the evtchn_upcall_pending mechanism is very similar to a
> level interrupt, however the mechanism to bring the notification to the
> guest is edge, even on x86.

How so?
In xen/arch/arm/domain.c I find:
> void vcpu_mark_events_pending(struct vcpu *v)
> {
>     int already_pending = test_and_set_bit(
>         0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
>
>     if ( already_pending )
>         return;

That smells very much like level to me.

>
>     vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
> }


> Even with the new vgic implementation it
> falls very naturally in the edge pattern of behaviors. This is one of
> those cases where I would be happy to deviate from the KVM
> implementation, because it makes sense and would be easier to maintain
> going forward. We can even get rid of vcpu_update_evtchn_irq.

So I tried this:
- remove vcpu_update_evtchn_irq()
- change type to edge in the hypervisor node of the DT
- allow changing the edge/level configuration of PPIs
- (optionally: ) remove the special vcpu_mark_events_pending() handling
(the one quoted above)

This boots Dom0, and I see the event IRQ being edge now.
But it hangs at various places when booting DomUs, both with and without
the last point applied.

So from all I can see the event channel IRQ is really a level IRQ:
- We have  a flag holding the *state*: edge IRQs are actually *events*.
- We set that flag in the hypervisor, but clear it in the domains.
- We don't inject new IRQs if that flag is still set.

A true edge IRQ mechanism would hand that event over to the interrupt
controller and then forget about it.

So I would like to *not* change this away from level this at this point:
- I don't have a working implementation of using edge IRQs.
- The existing level mechanism has shown no problems in weeks of testing.
- It's somewhat straining the architecture to allow configurable PPIs.

> I am OK with a not-ideal short term fix by the end of this week, as long
> as we come up with a proper fix later, by the release date. But in this
> instance, wouldn't be enough to change the PPI type to EDGE, remove
> vcpu_update_evtchn_irq, and be done with it?

Apparently not, sorry.

Cheers,
Andre.

>>> 3) vcpuA has to wait until trapping into Xen, calling
>>> vcpu_update_evtchn_irq, and going back to guest mode before receiving
>>> the event. This is theoretically a very long time.
>>>
>>>
>>> Instead what should happen is:
>>>
>>> 1) vcpuA/cpuA is running, it has already handled the event, cleared
>>> evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
>>> Xen yet. It is still in guest mode.
>>>
>>> 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
>>> vgic_inject_irq, which calls vgic_queue_irq_unlock that
>>> vcpu_kick(vcpuA), forcing it to take the event immediately.
>>>
>>> Am I right? Wouldn't it be safer to continue configuring the evtchn_irq
>>> as edge even in the new vgic?
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs()
  2018-03-28 18:47   ` Stefano Stabellini
@ 2018-03-29 14:57     ` Andre Przywara
  0 siblings, 0 replies; 122+ messages in thread
From: Andre Przywara @ 2018-03-29 14:57 UTC (permalink / raw)
  To: Stefano Stabellini; +Cc: xen-devel, Julien Grall

Hi,

On 28/03/18 19:47, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> When a VCPU moves to another CPU, we need to adjust the target affinity
>> of any hardware mapped vIRQs, to observe our "physical-follows-virtual"
>> policy.
>> Implement arch_move_irqs() to adjust the physical affinity of all hardware
>> mapped vIRQs targetting this VCPU.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>> ---
>>  xen/arch/arm/vgic/vgic.c | 39 +++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 39 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index ffab0b2635..23b8abfc5e 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -791,6 +791,45 @@ void gic_dump_vgic_info(struct vcpu *v)
>>      spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
>>  }
>>  
>> +/**
>> + * arch_move_irqs() - migrate the physical affinity of hardware mapped vIRQs
>> + * @v:  the vCPU, already assigned to the new pCPU
>> + *
>> + * arch_move_irqs() updates the physical affinity of all virtual IRQs
>> + * targetting this given vCPU. This only affects hardware mapped IRQs. The
>> + * new pCPU to target is already set in v->processor.
>> + * This is called by the core code after a vCPU has been migrated to a new
>> + * physical CPU.
>> + */
>> +void arch_move_irqs(struct vcpu *v)
>> +{
>> +    struct domain *d = v->domain;
>> +    unsigned int i;
>> +
>> +    /* We only target SPIs with this function */
>> +    for ( i = 0; i < d->arch.vgic.nr_spis; i++ )
>> +    {
>> +        struct vgic_irq *irq = vgic_get_irq(d, NULL, i + VGIC_NR_PRIVATE_IRQS);
>> +        unsigned long flags;
>> +
>> +        if ( !irq )
>> +            continue;
>> +
>> +        spin_lock_irqsave(&irq->irq_lock, flags);
>> +
>> +        /* only vIRQs that are not on a vCPU yet , but targetting this vCPU */
>> +        if ( irq->hw && !irq->vcpu && irq->target_vcpu == v)
>> +        {
> 
> In vgic_mmio_write_target, we change the physical irq affinity
> immediately, without checking for !irq->vcpu.

> I think it is OK because if a second interrupt for vcpuB comes in cpuB
> while it is still injected in vcpuA/cpuA, vgic_get_irq returns the same
> vgic_irq instance, vgic_inject_irq sets pending_latch to true.
> vgic_queue_irq_unlock does nothing because irq->vcpu is set. Then when
> vcpuA traps into Xen, vgic_prune_ap_list will take care of moving the
> vgic_irq to the ap_list belonging to vcpuB.
> 
> This seems to work, but don't we also need a vcpu_kick at the end of
> vgic_prune_ap_list to make sure the changes take effect in vcpuB? vcpuB
> could take an very long time to trap back into Xen again.

That seems like a valid question to me. But as KVM should be in the same
situation and there is no kick() there, I would like to forward this
question to Christoffer and Marc - who will probably not answer before
Tuesday. So I would ask for a followup fix if this is considered legitimate.

> But the real question is: why do we need to check for !irq->vcpu here?
> And worse: if an interrupt has irq->vcpu set, then who will take care of
> fixing the physical irq affinity later?

I think you are right, we don't need to consider irq->vcpu here. Similar
to what we now emulate, the affinity is only of concern for the *next*
IRQ to trigger. Currently handled IRQs are not affected, and a changed
affinity will not change anything for them.

> It looks like we should remove the "&& !irq->vcpu" here so that we can
> rely on the same mechanism already in place for ITARGETSR changes.
> However, would that work with already active interrupts? I think it
> should but I wanted to double check.

Looks all right to me, I will remove the "&& !irq->vcpu".

Cheers,
Andre.

>> +            irq_desc_t *desc = irq_to_desc(irq->hwintid);
>> +
>> +            irq_set_affinity(desc, cpumask_of(v->processor));
>> +        }
>> +
>> +        spin_unlock_irqrestore(&irq->irq_lock, flags);
>> +        vgic_put_irq(d, irq);
>> +    }
>> +}
>> +
>>  struct irq_desc *vgic_get_hw_irq_desc(struct domain *d, struct vcpu *v,
>>                                        unsigned int virq)
>>  {

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 33/39] ARM: new VGIC: Add preliminary stub implementation
  2018-03-27 22:48   ` Stefano Stabellini
@ 2018-04-03 13:22     ` Julien Grall
  0 siblings, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-04-03 13:22 UTC (permalink / raw)
  To: Stefano Stabellini, Andre Przywara; +Cc: xen-devel

Hi Stefano,

On 27/03/18 23:48, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> The ARM arch code requires an interrupt controller emulation to implement
>> vgic_clear_pending_irqs(), although it is suspected that it is actually
>> not necessary. Go with a stub for now to make the linker happy.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>> ---
>>   xen/arch/arm/vgic/vgic.c | 8 ++++++++
>>   1 file changed, 8 insertions(+)
>>
>> diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
>> index 23b8abfc5e..b70fdaaecb 100644
>> --- a/xen/arch/arm/vgic/vgic.c
>> +++ b/xen/arch/arm/vgic/vgic.c
>> @@ -791,6 +791,14 @@ void gic_dump_vgic_info(struct vcpu *v)
>>       spin_unlock_irqrestore(&v->arch.vgic.ap_list_lock, flags);
>>   }
>>   
>> +void vgic_clear_pending_irqs(struct vcpu *v)
>> +{
>> +    /*
>> +     * TODO: It is unclear whether we really need this, so we might instead
>> +     * remove it on the caller site.
>> +     */
>> +}
> 
> This is OK for now.
> 
> However, thinking about this issue, is it possible for a vcpu to send an
> interrupt to an offline vcpu, maybe an SGI? What would happen in that
> case? It looks like that vgic_mmio_write_sgir would allow it. Otherwise,
> a vcpu could cause the generation of a physical interrupt, an SPI,
> targeting an offline vcpu.
> 
> Maybe we should WARN in case ap_list is not empty?

The interrupts would be delivered when the vCPU is going online. It does 
not seem against the specification. Actually from the spec, it is valid 
to route an interrupt any vCPU (even non-existent one).

However, as I said on a previous version of this patch, the 
implementation on the current vGIC is just plain wrong for a few reasons:
         - lr_mask is reset but the LRs are not. This means when we 
context switch back, the LR might still be written and injecting 
unexpected interrupt (whoops).
         - both lists (inflight and pending) are cleared which means 
that a physical interrupt pending on that vCPU is lost forever (stay 
active in the physical so never going to fire again).

Furthermore, I don't think that Xen business to reset the GIC on cpu_on. 
If anything should be done, then is it on CPU_off to migrate the current 
interrupts to another vCPU. But IIRC the OS is responsible for that.

One the same note, similar problem would happen because of 
vgic_inject_irq would bail out on offline vCPU. This means that 
interrupt may be lost forever.

We are quite lucky that we don't use PSCI on/off very often in Xen.

Cheers,

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

* Re: [PATCH v3 06/39] ARM: evtchn: Handle level triggered IRQs correctly
  2018-03-28  0:01   ` Stefano Stabellini
  2018-03-28 15:39     ` Andre Przywara
@ 2018-04-03 13:34     ` Julien Grall
  1 sibling, 0 replies; 122+ messages in thread
From: Julien Grall @ 2018-04-03 13:34 UTC (permalink / raw)
  To: Stefano Stabellini, Andre Przywara; +Cc: xen-devel

Hi Stefano,

On 28/03/18 01:01, Stefano Stabellini wrote:
> On Wed, 21 Mar 2018, Andre Przywara wrote:
>> The event channel IRQ has level triggered semantics, however the current
>> VGIC treats everything as edge triggered.
>> To correctly process those IRQs, we have to lower the (virtual) IRQ line
>> at some point in time, depending on whether ther interrupt condition
>> still prevails.
>> Check the per-VCPU evtchn_upcall_pending variable to make the interrupt
>> line match its status, and call this function upon every hypervisor
>> entry.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> Reviewed-by: Julien Grall <julien.grall@arm.com>
>> ---
>>   xen/arch/arm/domain.c       | 7 +++++++
>>   xen/arch/arm/traps.c        | 1 +
>>   xen/include/asm-arm/event.h | 1 +
>>   3 files changed, 9 insertions(+)
>>
>> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
>> index ff97f2bc76..9688e62f78 100644
>> --- a/xen/arch/arm/domain.c
>> +++ b/xen/arch/arm/domain.c
>> @@ -953,6 +953,13 @@ void vcpu_mark_events_pending(struct vcpu *v)
>>       vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, true);
>>   }
>>   
>> +void vcpu_update_evtchn_irq(struct vcpu *v)
>> +{
>> +    bool pending = vcpu_info(v, evtchn_upcall_pending);
>> +
>> +    vgic_inject_irq(v->domain, v, v->domain->arch.evtchn_irq, pending);
>> +}
>> +
>>   /* The ARM spec declares that even if local irqs are masked in
>>    * the CPSR register, an irq should wake up a cpu from WFI anyway.
>>    * For this reason we need to check for irqs that need delivery,
>> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
>> index 2638446693..5c18e918b0 100644
>> --- a/xen/arch/arm/traps.c
>> +++ b/xen/arch/arm/traps.c
>> @@ -2033,6 +2033,7 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
>>            * trap and how it can be optimised.
>>            */
>>           vtimer_update_irqs(current);
>> +        vcpu_update_evtchn_irq(current);
>>   #endif
> 
> I am replying to this patch, even though I have already committed it, to
> point out a problem with the way we currently handle the evtchn_irq in
> this series.
> 
> The short version is that I think we should configure the PPI
> corresponding to the evtchn_irq as EDGE instead of LEVEL.
> 
> The long explanation follows, please correct me if I am wrong.
> 
> 1) vcpuA/cpuA is running, it has already handled the event, cleared
> evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> Xen yet. It is still in guest mode.
> 
> 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> vgic_inject_irq. However, because irq->line_level is high, it is not
> injected.
> 
> 3) vcpuA has to wait until trapping into Xen, calling
> vcpu_update_evtchn_irq, and going back to guest mode before receiving
> the event. This is theoretically a very long time.

Well, looking at the vGIC code the EOI bit in the LR is set for level 
interrupt. So as soon as vCPU A eoi it, we would enter to Xen and then 
call vcpu_update_evtchn_irq.

So I don't see how it could take a very long time.

Cheers,

> 
> 
> Instead what should happen is:
> 
> 1) vcpuA/cpuA is running, it has already handled the event, cleared
> evtchn_upcall_pending and EOIed the event_irq but hasn't trapped into
> Xen yet. It is still in guest mode.
> 
> 2) Xen on cpuB calls vcpu_mark_events_pending(vcpuA), then calls
> vgic_inject_irq, which calls vgic_queue_irq_unlock that
> vcpu_kick(vcpuA), forcing it to take the event immediately.
> 
> Am I right? Wouldn't it be safer to continue configuring the evtchn_irq
> as edge even in the new vgic?
> 

-- 
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

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

end of thread, other threads:[~2018-04-03 13:34 UTC | newest]

Thread overview: 122+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-21 16:31 [PATCH v3 00/39] New VGIC(-v2) implementation Andre Przywara
2018-03-21 16:31 ` [PATCH v3 01/39] xen/arm: gic: Read unconditionally the source from the LRs Andre Przywara
2018-03-21 16:31 ` [PATCH v3 02/39] ARM: GIC: add GIC_INVALID to enum gic_version Andre Przywara
2018-03-22  1:39   ` Julien Grall
2018-03-26 20:08   ` Stefano Stabellini
2018-03-21 16:31 ` [PATCH v3 03/39] ARM: GIC: Allow tweaking the active and pending state of an IRQ Andre Przywara
2018-03-22  1:51   ` Julien Grall
2018-03-22 11:11     ` Andre Przywara
2018-03-21 16:32 ` [PATCH v3 04/39] ARM: GIC: Allow reading pending state of a hardware IRQ Andre Przywara
2018-03-26 20:08   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 05/39] ARM: timer: Handle level triggered IRQs correctly Andre Przywara
2018-03-22  1:58   ` Julien Grall
2018-03-26 20:28   ` Stefano Stabellini
2018-03-27 13:06     ` Andre Przywara
2018-03-27 18:17       ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 06/39] ARM: evtchn: " Andre Przywara
2018-03-22  2:08   ` Julien Grall
2018-03-26 20:08   ` Stefano Stabellini
2018-03-28  0:01   ` Stefano Stabellini
2018-03-28 15:39     ` Andre Przywara
2018-03-28 17:46       ` Stefano Stabellini
2018-03-29  0:34         ` Julien Grall
2018-03-29 13:44         ` Andre Przywara
2018-04-03 13:34     ` Julien Grall
2018-03-21 16:32 ` [PATCH v3 07/39] ARM: vPL011: Use the VGIC's level triggered IRQs handling if available Andre Przywara
2018-03-26 20:20   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 08/39] ARM: new VGIC: Add data structure definitions Andre Przywara
2018-03-26 20:41   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 09/39] ARM: new VGIC: Add accessor to new struct vgic_irq instance Andre Przywara
2018-03-22  2:11   ` Julien Grall
2018-03-26 20:46     ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 10/39] ARM: new VGIC: Implement virtual IRQ injection Andre Przywara
2018-03-26 21:01   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 11/39] Add list_sort() routine from Linux Andre Przywara
2018-03-21 17:01   ` Jan Beulich
2018-03-22  2:14   ` Julien Grall
2018-03-21 16:32 ` [PATCH v3 12/39] ARM: new VGIC: Add IRQ sorting Andre Przywara
2018-03-26 21:16   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 13/39] ARM: new VGIC: Add IRQ sync/flush framework Andre Przywara
2018-03-22  2:16   ` Julien Grall
2018-03-26 21:30   ` Stefano Stabellini
2018-03-27 13:23     ` Andre Przywara
2018-03-27 18:55       ` Stefano Stabellini
2018-03-27 19:20         ` Stefano Stabellini
2018-03-27 22:13           ` André Przywara
2018-03-21 16:32 ` [PATCH v3 14/39] ARM: new VGIC: Add GICv2 world switch backend Andre Przywara
2018-03-22  3:48   ` Julien Grall
2018-03-22 11:04     ` Andre Przywara
2018-03-22 13:55       ` Julien Grall
2018-03-21 16:32 ` [PATCH v3 15/39] ARM: new VGIC: Implement vgic_vcpu_pending_irq Andre Przywara
2018-03-22  3:52   ` Julien Grall
2018-03-22 11:15     ` Andre Przywara
2018-03-26 23:34       ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 16/39] ARM: new VGIC: Add MMIO handling framework Andre Przywara
2018-03-27 20:07   ` Stefano Stabellini
2018-03-28  9:28     ` Andre Przywara
2018-03-21 16:32 ` [PATCH v3 17/39] ARM: new VGIC: Add GICv2 " Andre Przywara
2018-03-27 20:28   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 18/39] ARM: new VGIC: Add CTLR, TYPER and IIDR handlers Andre Przywara
2018-03-22  7:33   ` Julien Grall
2018-03-27 20:38   ` Stefano Stabellini
2018-03-28 10:36     ` Andre Przywara
2018-03-28 17:20       ` Stefano Stabellini
2018-03-28 17:22       ` [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 19/39] ARM: new VGIC: Add ENABLE registers handlers Andre Przywara
2018-03-27 21:06   ` Stefano Stabellini
2018-03-28  9:09     ` Andre Przywara
2018-03-28 17:19       ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 20/39] ARM: new VGIC: Add PENDING " Andre Przywara
2018-03-27 21:14   ` Stefano Stabellini
2018-03-28 14:10     ` Andre Przywara
2018-03-21 16:32 ` [PATCH v3 21/39] ARM: new VGIC: Add ACTIVE " Andre Przywara
2018-03-27 21:21   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 22/39] ARM: new VGIC: Add PRIORITY " Andre Przywara
2018-03-27 21:24   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 23/39] ARM: new VGIC: Add CONFIG " Andre Przywara
2018-03-27 21:26   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 24/39] ARM: new VGIC: Add TARGET " Andre Przywara
2018-03-27  0:24   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 25/39] ARM: new VGIC: Add SGIR register handler Andre Przywara
2018-03-22  7:54   ` Julien Grall
2018-03-27 22:23   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 26/39] ARM: new VGIC: Add SGIPENDR register handlers Andre Przywara
2018-03-27 22:27   ` Stefano Stabellini
2018-03-28 10:37     ` Andre Przywara
2018-03-21 16:32 ` [PATCH v3 27/39] ARM: new VGIC: Handle hardware mapped IRQs Andre Przywara
2018-03-27 22:31   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 28/39] ARM: new VGIC: Add event channel IRQ handling Andre Przywara
2018-03-27 22:33   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 29/39] ARM: new VGIC: Handle virtual IRQ allocation/reservation Andre Przywara
2018-03-27 22:38   ` Stefano Stabellini
2018-03-28  9:17     ` Andre Przywara
2018-03-21 16:32 ` [PATCH v3 30/39] ARM: new VGIC: Dump virtual IRQ info Andre Przywara
2018-03-27 22:39   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 31/39] ARM: new VGIC: Provide system register emulation stub Andre Przywara
2018-03-27 22:40   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 32/39] ARM: new VGIC: Implement arch_move_irqs() Andre Przywara
2018-03-26 23:46   ` Stefano Stabellini
2018-03-28 18:47   ` Stefano Stabellini
2018-03-29 14:57     ` Andre Przywara
2018-03-21 16:32 ` [PATCH v3 33/39] ARM: new VGIC: Add preliminary stub implementation Andre Przywara
2018-03-27 22:48   ` Stefano Stabellini
2018-04-03 13:22     ` Julien Grall
2018-03-21 16:32 ` [PATCH v3 34/39] ARM: new VGIC: vgic-init: register VGIC Andre Przywara
2018-03-22  8:00   ` Julien Grall
2018-03-22 11:18     ` Andre Przywara
2018-03-27 22:50     ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 35/39] ARM: new VGIC: Add vgic_v2_enable Andre Przywara
2018-03-27 22:51   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 36/39] ARM: new VGIC: vgic-init: implement vgic_init Andre Przywara
2018-03-22  8:01   ` Julien Grall
2018-03-27 23:16   ` Stefano Stabellini
2018-03-28  0:06     ` Stefano Stabellini
2018-03-28 10:49     ` Andre Przywara
2018-03-21 16:32 ` [PATCH v3 37/39] ARM: new VGIC: vgic-init: implement map_resources Andre Przywara
2018-03-27 23:09   ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 38/39] ARM: new VGIC: Allocate two pages for struct vcpu Andre Przywara
2018-03-22  8:11   ` Julien Grall
2018-03-27 23:07     ` Stefano Stabellini
2018-03-21 16:32 ` [PATCH v3 39/39] ARM: VGIC: wire new VGIC(-v2) files into Xen build system Andre Przywara
2018-03-22  8:16   ` Julien Grall
2018-03-22 10:39     ` Andre Przywara

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.