All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/24] vITS save/restore
@ 2017-05-06 15:24 ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

This series specifies and implements an API aimed at saving and restoring
the state of the in-kernel emulated ITS device.

The ITS is programmed through registers and tables. Those latter
are allocated by the guest. Their base address is programmed in
registers or table entries before the ITS is enabled.

The ITS is free to use some of them to flush its internal caches. This
is likely to be used when entering low power state.

Therefore, for save/restore use case, it looks natural to use this
guest RAM allocated space to save the table related data. However,
currently, The ITS in-kernel emulated device does not use all of those
tables and for those it uses, it does not always sync them with its
cached data. Additional sync must happen for:
- the collection table
- the device table
- the per-device translation tables
- the LPI pending tables.

The LPI configuration table and the command queues do not need extra
syncs.

Best Regards

Eric

Git: complete series available at
https://github.com/eauger/linux/tree/v4.11-its-mig-v7

* Testing:
- on Cavium ThunderX using a virtio-net-pci guest,
  virsh save/restore commands and virt-manager live migration.
  Tested with 1 and 2 stage device table.

History:
v6 -> v7:
- small rewording in the ABI spec
- hold its lock during save and restore
- check alignment of the offset also on vgic_its_has_attr_regs
- collected A-b/R-b
- use NR_ITS_ABIS
- mask revision with GITS_IIDR_REV_MASK
- some typo & comment fixes

- the only comment I have not yet taken into account is removal of
  map_resources().

v5 -> v6:
- address Christoffer's comments:
  - add restore sequence in the doc
  - sync with pending and config tables in its_add_lpi
  - change in return values when scanning the tables
  - several bug fixes pointed out by Christoffer
  - see full details in individual logs

v4 -> v5:
- user API changes:
  - ITS table save/restore triggered through ITS KVM device
    KVM_DEV_ARM_VGIC_GRP_CTRL group, KVM_DEV_ARM_ITS_SAVE_TABLES,
    KVM_DEV_ARM_ITS_RESTORE_TABLES
  - RDIST pending table flush triggered through GICV3 KVM device
    KVM_DEV_ARM_VGIC_GRP_CTRL/KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
- Introduce an ABI infrastructure, entry size report using this infra
- IIDR reports ABI chosen set by userspace if any
- pending table save moved to vgic-v3.c
- use optimisation in pending table save
- check target_addr when restore cte
- pending table sync called from restore_tables
- added KVM: arm64: vgic-its: Fix pending table sync
- simplify loopup_table and use kvm_read_guest()
- sort the device and ITE list on save
- add defines for shifts and masks, GIC_ENCODE_SZ macro

v3 -> v4:
- update the DTE format (ITT_addr 52 bit support, validity bit addition)
- Document ABI revision and implement check
- iidr save/restore (including a new patch for iidr user write access)
- changed locking: kvm lock + vcpu lock
- fix nb_eventid_bits mixup
- 2 new patches aiming at exposing next_segment() and lock_all_vcpus()
- rework errror handling of lookup_table functions

- I took into account all Andre's comments/suggestions except:
  - trigger the save/restore of pending tables from GICV3 KVM device
    instead of ITS KVM device
  - implement ITS flush/restore in KVM_DEV_ARM_VGIC_GRP_CTRL
    ITS group

See the ML replies for current justifications. In case other people
strongly disagree of course I will change the code.

v2 -> v3:
- fix restore ITS ITT_addr bit masking

v1 -> v2:
- rebased on Vijaya's v11
- all entries now are 8 byte large
- devid/eventid indexing for device table and ITT
- support 2 stage device table
- common infra to read indexed tables
- add cpu <-> le64 conversions
- itte renamed into ite
- do not care anymore about pending table 1st KB
  (not needed at the moment for coarse mapping)

RFC v1
- creation


Eric Auger (24):
  KVM: arm/arm64: Add ITS save/restore API documentation
  KVM: arm/arm64: Add GICV3 pending table save API documentation
  KVM: arm/arm64: vgic-its: rename itte into ite
  arm/arm64: vgic: turn vgic_find_mmio_region into public
  KVM: arm64: vgic-its: KVM_DEV_ARM_VGIC_GRP_ITS_REGS group
  KVM: arm/arm64: vgic: expose (un)lock_all_vcpus
  KVM: arm64: vgic-its: Implement vgic_its_has_attr_regs and
    attr_regs_access
  KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_creadr
  KVM: arm64: vgic-its: Introduce migration ABI infrastructure
  KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_iidr
  KVM: arm64: vgic-its: Interpret MAPD Size field and check related
    errors
  KVM: arm64: vgic-its: Interpret MAPD ITT_addr field
  KVM: arm64: vgic-its: Check the device id matches TYPER DEVBITS range
  KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
  KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
  KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  KVM: arm64: vgic-its: vgic_its_alloc_ite/device
  KVM: arm64: vgic-its: Add infrastructure for table lookup
  KVM: arm64: vgic-its: Collection table save/restore
  KVM: arm64: vgic-its: vgic_its_check_id returns the entry's GPA
  KVM: arm64: vgic-its: Device table save/restore
  KVM: arm64: vgic-its: ITT save and restore
  KVM: arm64: vgic-its: Fix pending table sync
  KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES

 Documentation/virtual/kvm/devices/arm-vgic-its.txt |  120 ++
 Documentation/virtual/kvm/devices/arm-vgic-v3.txt  |    6 +
 arch/arm/include/uapi/asm/kvm.h                    |    6 +-
 arch/arm64/include/uapi/asm/kvm.h                  |    6 +-
 include/kvm/arm_vgic.h                             |    3 +
 include/linux/irqchip/arm-gic-v3.h                 |   14 +
 virt/kvm/arm/vgic/vgic-its.c                       | 1164 +++++++++++++++++---
 virt/kvm/arm/vgic/vgic-kvm-device.c                |   24 +-
 virt/kvm/arm/vgic/vgic-mmio.c                      |   11 +-
 virt/kvm/arm/vgic/vgic-mmio.h                      |   14 +-
 virt/kvm/arm/vgic/vgic-v3.c                        |   95 ++
 virt/kvm/arm/vgic/vgic.h                           |   28 +
 12 files changed, 1349 insertions(+), 142 deletions(-)

-- 
2.5.5

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

* [PATCH v7 00/24] vITS save/restore
@ 2017-05-06 15:24 ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

This series specifies and implements an API aimed at saving and restoring
the state of the in-kernel emulated ITS device.

The ITS is programmed through registers and tables. Those latter
are allocated by the guest. Their base address is programmed in
registers or table entries before the ITS is enabled.

The ITS is free to use some of them to flush its internal caches. This
is likely to be used when entering low power state.

Therefore, for save/restore use case, it looks natural to use this
guest RAM allocated space to save the table related data. However,
currently, The ITS in-kernel emulated device does not use all of those
tables and for those it uses, it does not always sync them with its
cached data. Additional sync must happen for:
- the collection table
- the device table
- the per-device translation tables
- the LPI pending tables.

The LPI configuration table and the command queues do not need extra
syncs.

Best Regards

Eric

Git: complete series available at
https://github.com/eauger/linux/tree/v4.11-its-mig-v7

* Testing:
- on Cavium ThunderX using a virtio-net-pci guest,
  virsh save/restore commands and virt-manager live migration.
  Tested with 1 and 2 stage device table.

History:
v6 -> v7:
- small rewording in the ABI spec
- hold its lock during save and restore
- check alignment of the offset also on vgic_its_has_attr_regs
- collected A-b/R-b
- use NR_ITS_ABIS
- mask revision with GITS_IIDR_REV_MASK
- some typo & comment fixes

- the only comment I have not yet taken into account is removal of
  map_resources().

v5 -> v6:
- address Christoffer's comments:
  - add restore sequence in the doc
  - sync with pending and config tables in its_add_lpi
  - change in return values when scanning the tables
  - several bug fixes pointed out by Christoffer
  - see full details in individual logs

v4 -> v5:
- user API changes:
  - ITS table save/restore triggered through ITS KVM device
    KVM_DEV_ARM_VGIC_GRP_CTRL group, KVM_DEV_ARM_ITS_SAVE_TABLES,
    KVM_DEV_ARM_ITS_RESTORE_TABLES
  - RDIST pending table flush triggered through GICV3 KVM device
    KVM_DEV_ARM_VGIC_GRP_CTRL/KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
- Introduce an ABI infrastructure, entry size report using this infra
- IIDR reports ABI chosen set by userspace if any
- pending table save moved to vgic-v3.c
- use optimisation in pending table save
- check target_addr when restore cte
- pending table sync called from restore_tables
- added KVM: arm64: vgic-its: Fix pending table sync
- simplify loopup_table and use kvm_read_guest()
- sort the device and ITE list on save
- add defines for shifts and masks, GIC_ENCODE_SZ macro

v3 -> v4:
- update the DTE format (ITT_addr 52 bit support, validity bit addition)
- Document ABI revision and implement check
- iidr save/restore (including a new patch for iidr user write access)
- changed locking: kvm lock + vcpu lock
- fix nb_eventid_bits mixup
- 2 new patches aiming at exposing next_segment() and lock_all_vcpus()
- rework errror handling of lookup_table functions

- I took into account all Andre's comments/suggestions except:
  - trigger the save/restore of pending tables from GICV3 KVM device
    instead of ITS KVM device
  - implement ITS flush/restore in KVM_DEV_ARM_VGIC_GRP_CTRL
    ITS group

See the ML replies for current justifications. In case other people
strongly disagree of course I will change the code.

v2 -> v3:
- fix restore ITS ITT_addr bit masking

v1 -> v2:
- rebased on Vijaya's v11
- all entries now are 8 byte large
- devid/eventid indexing for device table and ITT
- support 2 stage device table
- common infra to read indexed tables
- add cpu <-> le64 conversions
- itte renamed into ite
- do not care anymore about pending table 1st KB
  (not needed at the moment for coarse mapping)

RFC v1
- creation


Eric Auger (24):
  KVM: arm/arm64: Add ITS save/restore API documentation
  KVM: arm/arm64: Add GICV3 pending table save API documentation
  KVM: arm/arm64: vgic-its: rename itte into ite
  arm/arm64: vgic: turn vgic_find_mmio_region into public
  KVM: arm64: vgic-its: KVM_DEV_ARM_VGIC_GRP_ITS_REGS group
  KVM: arm/arm64: vgic: expose (un)lock_all_vcpus
  KVM: arm64: vgic-its: Implement vgic_its_has_attr_regs and
    attr_regs_access
  KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_creadr
  KVM: arm64: vgic-its: Introduce migration ABI infrastructure
  KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_iidr
  KVM: arm64: vgic-its: Interpret MAPD Size field and check related
    errors
  KVM: arm64: vgic-its: Interpret MAPD ITT_addr field
  KVM: arm64: vgic-its: Check the device id matches TYPER DEVBITS range
  KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
  KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
  KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  KVM: arm64: vgic-its: vgic_its_alloc_ite/device
  KVM: arm64: vgic-its: Add infrastructure for table lookup
  KVM: arm64: vgic-its: Collection table save/restore
  KVM: arm64: vgic-its: vgic_its_check_id returns the entry's GPA
  KVM: arm64: vgic-its: Device table save/restore
  KVM: arm64: vgic-its: ITT save and restore
  KVM: arm64: vgic-its: Fix pending table sync
  KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES

 Documentation/virtual/kvm/devices/arm-vgic-its.txt |  120 ++
 Documentation/virtual/kvm/devices/arm-vgic-v3.txt  |    6 +
 arch/arm/include/uapi/asm/kvm.h                    |    6 +-
 arch/arm64/include/uapi/asm/kvm.h                  |    6 +-
 include/kvm/arm_vgic.h                             |    3 +
 include/linux/irqchip/arm-gic-v3.h                 |   14 +
 virt/kvm/arm/vgic/vgic-its.c                       | 1164 +++++++++++++++++---
 virt/kvm/arm/vgic/vgic-kvm-device.c                |   24 +-
 virt/kvm/arm/vgic/vgic-mmio.c                      |   11 +-
 virt/kvm/arm/vgic/vgic-mmio.h                      |   14 +-
 virt/kvm/arm/vgic/vgic-v3.c                        |   95 ++
 virt/kvm/arm/vgic/vgic.h                           |   28 +
 12 files changed, 1349 insertions(+), 142 deletions(-)

-- 
2.5.5

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

* [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

Add description for how to access ITS registers and how to save/restore
ITS tables into/from memory.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- rephrase ordering sequence + few cosmetic changes

v5 -> v6:
- add restoration ordering
- 256B -> 256 Byte aligned
- DTE Size is number of bits for the EVENTID
- s/GITS_READR/GITS_CREADR

v4 -> v5:
- take into account Christoffer's comments
- pending table save on GICV3 side now

v3 -> v4:
- take into account Peter's comments:
  - typos
  - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
  - add a validity bit in DTE
  - document all fields in CTE and ITE
  - document ABI revision
- take into account Andre's comments:
  - document restrictions about GITS_CREADR writing and GITS_IIDR
  - document -EBUSY error if one or more VCPUS are runnning
  - document 64b registers only can be accessed with 64b access
- itt_addr field matches bits [51:8] of the itt_addr

v1 -> v2:
- DTE and ITE now are 8 bytes
- DTE and ITE now indexed by deviceid/eventid
- use ITE name instead of ITTE
- mentions ITT_addr matches bits [51:8] of the actual address
- mentions LE layout
---
 Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
index 6081a5b..ba132e9 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
@@ -32,7 +32,127 @@ Groups:
     KVM_DEV_ARM_VGIC_CTRL_INIT
       request the initialization of the ITS, no additional parameter in
       kvm_device_attr.addr.
+
+    KVM_DEV_ARM_ITS_SAVE_TABLES
+      save the ITS table data into guest RAM, at the location provisioned
+      by the guest in corresponding registers/table entries.
+
+      The layout of the tables in guest memory defines an ABI. The entries
+      are laid out in little endian format as described in the last paragraph.
+
+    KVM_DEV_ARM_ITS_RESTORE_TABLES
+      restore the ITS tables from guest RAM to ITS internal structures.
+
+      The GICV3 must be restored before the ITS and all ITS registers but
+      the GITS_CTLR must be restored before restoring the ITS tables.
+
+      The GITS_IIDR read-only register must also be restored before
+      calling KVM_DEV_ARM_ITS_RESTORE_TABLES as the IIDR revision field
+      encodes the ABI revision.
+
+      The expected ordering when restoring the GICv3/ITS is described in section
+      "ITS Restore Sequence".
+
   Errors:
     -ENXIO:  ITS not properly configured as required prior to setting
              this attribute
     -ENOMEM: Memory shortage when allocating ITS internal data
+    -EINVAL: Inconsistent restored data
+    -EFAULT: Invalid guest ram access
+    -EBUSY:  One or more VCPUS are running
+
+  KVM_DEV_ARM_VGIC_GRP_ITS_REGS
+  Attributes:
+      The attr field of kvm_device_attr encodes the offset of the
+      ITS register, relative to the ITS control frame base address
+      (ITS_base).
+
+      kvm_device_attr.addr points to a __u64 value whatever the width
+      of the addressed register (32/64 bits). 64 bit registers can only
+      be accessed with full length.
+
+      Writes to read-only registers are ignored by the kernel except for:
+      - GITS_CREADR. It must be restored otherwise commands in the queue
+        will be re-executed after restoring CWRITER. GITS_CREADR must be
+        restored before restoring the GITS_CTLR which is likely to enable the
+        ITS. Also it must be restored after GITS_CBASER since a write to
+        GITS_CBASER resets GITS_CREADR.
+      - GITS_IIDR. The Revision field encodes the table layout ABI revision.
+        In the future we might implement direct injection of virtual LPIs.
+        This will require an upgrade of the table layout and an evolution of
+        the ABI. GITS_IIDR must be restored before calling
+        KVM_DEV_ARM_ITS_RESTORE_TABLES.
+
+      For other registers, getting or setting a register has the same
+      effect as reading/writing the register on real hardware.
+  Errors:
+    -ENXIO: Offset does not correspond to any supported register
+    -EFAULT: Invalid user pointer for attr->addr
+    -EINVAL: Offset is not 64-bit aligned
+    -EBUSY: one or more VCPUS are running
+
+ ITS Restore Sequence:
+ -------------------------
+
+The following ordering must be followed when restoring the GIC and the ITS:
+a) restore all guest memory and create vcpus
+b) restore all redistributors
+c) initialize the ITS and then provide its base address
+   (KVM_DEV_ARM_VGIC_CTRL_INIT, KVM_DEV_ARM_VGIC_GRP_ADDR)
+d) restore the ITS in the following order:
+   1. Restore GITS_CBASER
+   2. Restore all other GITS_ registers, except GITS_CTLR!
+   3. Load the ITS table data (KVM_DEV_ARM_ITS_RESTORE_TABLES)
+   4. Restore GITS_CTLR
+
+Then vcpus can be started.
+
+ ITS Table ABI REV0:
+ -------------------
+
+ Revision 0 of the ABI only supports physical LPIs.
+
+ The device table and ITT are indexed by the deviceid and eventid,
+ respectively. The collection table is not indexed by collectionid:
+ CTEs are written in the table in the order of collection creation. All
+ entries are 8 bytes.
+
+ Device Table Entry (DTE):
+
+ bits:     | 63| 62 ... 49 | 48 ... 5 | 4 ... 0 |
+ values:   | V |   next    | ITT_addr |  Size   |
+
+ where;
+ - V indicates whether the entry is valid. If not, other fields
+   are not meaningful.
+ - next: equals to 0 if this entry is the last one; otherwise it
+   corresponds to the deviceid offset to the next DTE, capped by
+   2^14 -1.
+ - ITT_addr matches bits [51:8] of the ITT address (256 Byte aligned).
+ - Size specifies the supported number of bits for the eventid,
+   minus one
+
+ Collection Table Entry (CTE):
+
+ bits:     | 63| 62 ..  52  | 51 ... 16 | 15  ...   0 |
+ values:   | V |    RES0    |  RDBase   |    ICID     |
+
+ where:
+ - V indicates whether the entry is valid. If not, other fields are
+   not meaningful.
+ - RES0: reserved field with Should-Be-Zero-or-Preserved behavior.
+ - RDBase is the PE number (GICR_TYPER.Processor_Number semantic),
+ - ICID is the collection ID
+
+ Interrupt Translation Entry (ITE):
+
+ bits:     | 63 ... 48 | 47 ... 16 | 15 ... 0 |
+ values:   |    next   |   pINTID  |  ICID    |
+
+ where:
+ - next: equals to 0 if this entry is the last one; otherwise it corresponds
+   to the eventid offset to the next ITE capped by 2^16 -1.
+ - pINTID is the physical LPI ID; if zero, it means the entry is not valid
+   and other fields are not meaningful.
+ - ICID is the collection ID
+
-- 
2.5.5

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

* [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Add description for how to access ITS registers and how to save/restore
ITS tables into/from memory.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- rephrase ordering sequence + few cosmetic changes

v5 -> v6:
- add restoration ordering
- 256B -> 256 Byte aligned
- DTE Size is number of bits for the EVENTID
- s/GITS_READR/GITS_CREADR

v4 -> v5:
- take into account Christoffer's comments
- pending table save on GICV3 side now

v3 -> v4:
- take into account Peter's comments:
  - typos
  - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
  - add a validity bit in DTE
  - document all fields in CTE and ITE
  - document ABI revision
- take into account Andre's comments:
  - document restrictions about GITS_CREADR writing and GITS_IIDR
  - document -EBUSY error if one or more VCPUS are runnning
  - document 64b registers only can be accessed with 64b access
- itt_addr field matches bits [51:8] of the itt_addr

v1 -> v2:
- DTE and ITE now are 8 bytes
- DTE and ITE now indexed by deviceid/eventid
- use ITE name instead of ITTE
- mentions ITT_addr matches bits [51:8] of the actual address
- mentions LE layout
---
 Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
index 6081a5b..ba132e9 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
@@ -32,7 +32,127 @@ Groups:
     KVM_DEV_ARM_VGIC_CTRL_INIT
       request the initialization of the ITS, no additional parameter in
       kvm_device_attr.addr.
+
+    KVM_DEV_ARM_ITS_SAVE_TABLES
+      save the ITS table data into guest RAM, at the location provisioned
+      by the guest in corresponding registers/table entries.
+
+      The layout of the tables in guest memory defines an ABI. The entries
+      are laid out in little endian format as described in the last paragraph.
+
+    KVM_DEV_ARM_ITS_RESTORE_TABLES
+      restore the ITS tables from guest RAM to ITS internal structures.
+
+      The GICV3 must be restored before the ITS and all ITS registers but
+      the GITS_CTLR must be restored before restoring the ITS tables.
+
+      The GITS_IIDR read-only register must also be restored before
+      calling KVM_DEV_ARM_ITS_RESTORE_TABLES as the IIDR revision field
+      encodes the ABI revision.
+
+      The expected ordering when restoring the GICv3/ITS is described in section
+      "ITS Restore Sequence".
+
   Errors:
     -ENXIO:  ITS not properly configured as required prior to setting
              this attribute
     -ENOMEM: Memory shortage when allocating ITS internal data
+    -EINVAL: Inconsistent restored data
+    -EFAULT: Invalid guest ram access
+    -EBUSY:  One or more VCPUS are running
+
+  KVM_DEV_ARM_VGIC_GRP_ITS_REGS
+  Attributes:
+      The attr field of kvm_device_attr encodes the offset of the
+      ITS register, relative to the ITS control frame base address
+      (ITS_base).
+
+      kvm_device_attr.addr points to a __u64 value whatever the width
+      of the addressed register (32/64 bits). 64 bit registers can only
+      be accessed with full length.
+
+      Writes to read-only registers are ignored by the kernel except for:
+      - GITS_CREADR. It must be restored otherwise commands in the queue
+        will be re-executed after restoring CWRITER. GITS_CREADR must be
+        restored before restoring the GITS_CTLR which is likely to enable the
+        ITS. Also it must be restored after GITS_CBASER since a write to
+        GITS_CBASER resets GITS_CREADR.
+      - GITS_IIDR. The Revision field encodes the table layout ABI revision.
+        In the future we might implement direct injection of virtual LPIs.
+        This will require an upgrade of the table layout and an evolution of
+        the ABI. GITS_IIDR must be restored before calling
+        KVM_DEV_ARM_ITS_RESTORE_TABLES.
+
+      For other registers, getting or setting a register has the same
+      effect as reading/writing the register on real hardware.
+  Errors:
+    -ENXIO: Offset does not correspond to any supported register
+    -EFAULT: Invalid user pointer for attr->addr
+    -EINVAL: Offset is not 64-bit aligned
+    -EBUSY: one or more VCPUS are running
+
+ ITS Restore Sequence:
+ -------------------------
+
+The following ordering must be followed when restoring the GIC and the ITS:
+a) restore all guest memory and create vcpus
+b) restore all redistributors
+c) initialize the ITS and then provide its base address
+   (KVM_DEV_ARM_VGIC_CTRL_INIT, KVM_DEV_ARM_VGIC_GRP_ADDR)
+d) restore the ITS in the following order:
+   1. Restore GITS_CBASER
+   2. Restore all other GITS_ registers, except GITS_CTLR!
+   3. Load the ITS table data (KVM_DEV_ARM_ITS_RESTORE_TABLES)
+   4. Restore GITS_CTLR
+
+Then vcpus can be started.
+
+ ITS Table ABI REV0:
+ -------------------
+
+ Revision 0 of the ABI only supports physical LPIs.
+
+ The device table and ITT are indexed by the deviceid and eventid,
+ respectively. The collection table is not indexed by collectionid:
+ CTEs are written in the table in the order of collection creation. All
+ entries are 8 bytes.
+
+ Device Table Entry (DTE):
+
+ bits:     | 63| 62 ... 49 | 48 ... 5 | 4 ... 0 |
+ values:   | V |   next    | ITT_addr |  Size   |
+
+ where;
+ - V indicates whether the entry is valid. If not, other fields
+   are not meaningful.
+ - next: equals to 0 if this entry is the last one; otherwise it
+   corresponds to the deviceid offset to the next DTE, capped by
+   2^14 -1.
+ - ITT_addr matches bits [51:8] of the ITT address (256 Byte aligned).
+ - Size specifies the supported number of bits for the eventid,
+   minus one
+
+ Collection Table Entry (CTE):
+
+ bits:     | 63| 62 ..  52  | 51 ... 16 | 15  ...   0 |
+ values:   | V |    RES0    |  RDBase   |    ICID     |
+
+ where:
+ - V indicates whether the entry is valid. If not, other fields are
+   not meaningful.
+ - RES0: reserved field with Should-Be-Zero-or-Preserved behavior.
+ - RDBase is the PE number (GICR_TYPER.Processor_Number semantic),
+ - ICID is the collection ID
+
+ Interrupt Translation Entry (ITE):
+
+ bits:     | 63 ... 48 | 47 ... 16 | 15 ... 0 |
+ values:   |    next   |   pINTID  |  ICID    |
+
+ where:
+ - next: equals to 0 if this entry is the last one; otherwise it corresponds
+   to the eventid offset to the next ITE capped by 2^16 -1.
+ - pINTID is the physical LPI ID; if zero, it means the entry is not valid
+   and other fields are not meaningful.
+ - ICID is the collection ID
+
-- 
2.5.5

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

* [PATCH v7 02/24] KVM: arm/arm64: Add GICV3 pending table save API documentation
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

Add description for how to save GICV3 LPI pending bit into
guest RAM pending tables.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- Added Christoffer's A-b

v5: creation
---
 Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
index c1a2461..9293b45 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -167,11 +167,17 @@ Groups:
     KVM_DEV_ARM_VGIC_CTRL_INIT
       request the initialization of the VGIC, no additional parameter in
       kvm_device_attr.addr.
+    KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
+      save all LPI pending bits into guest RAM pending tables.
+
+      The first kB of the pending table is not altered by this operation.
   Errors:
     -ENXIO: VGIC not properly configured as required prior to calling
      this attribute
     -ENODEV: no online VCPU
     -ENOMEM: memory shortage when allocating vgic internal data
+    -EFAULT: Invalid guest ram access
+    -EBUSY:  One or more VCPUS are running
 
 
   KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO
-- 
2.5.5

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

* [PATCH v7 02/24] KVM: arm/arm64: Add GICV3 pending table save API documentation
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Add description for how to save GICV3 LPI pending bit into
guest RAM pending tables.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- Added Christoffer's A-b

v5: creation
---
 Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
index c1a2461..9293b45 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -167,11 +167,17 @@ Groups:
     KVM_DEV_ARM_VGIC_CTRL_INIT
       request the initialization of the VGIC, no additional parameter in
       kvm_device_attr.addr.
+    KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
+      save all LPI pending bits into guest RAM pending tables.
+
+      The first kB of the pending table is not altered by this operation.
   Errors:
     -ENXIO: VGIC not properly configured as required prior to calling
      this attribute
     -ENODEV: no online VCPU
     -ENOMEM: memory shortage when allocating vgic internal data
+    -EFAULT: Invalid guest ram access
+    -EBUSY:  One or more VCPUS are running
 
 
   KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO
-- 
2.5.5

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

* [PATCH v7 03/24] KVM: arm/arm64: vgic-its: rename itte into ite
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

The actual abbreviation for the interrupt translation table entry
is ITE. Let's rename all itte instances by ite.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's A-b

v5: Add Marc's A-b
---
 virt/kvm/arm/vgic/vgic-its.c | 148 +++++++++++++++++++++----------------------
 1 file changed, 74 insertions(+), 74 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 8d1da1a..3ffcbbe 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -114,8 +114,8 @@ struct its_collection {
 #define its_is_collection_mapped(coll) ((coll) && \
 				((coll)->target_addr != COLLECTION_NOT_MAPPED))
 
-struct its_itte {
-	struct list_head itte_list;
+struct its_ite {
+	struct list_head ite_list;
 
 	struct vgic_irq *irq;
 	struct its_collection *collection;
@@ -143,27 +143,27 @@ static struct its_device *find_its_device(struct vgic_its *its, u32 device_id)
  * Device ID/Event ID pair on an ITS.
  * Must be called with the its_lock mutex held.
  */
-static struct its_itte *find_itte(struct vgic_its *its, u32 device_id,
+static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 				  u32 event_id)
 {
 	struct its_device *device;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 	device = find_its_device(its, device_id);
 	if (device == NULL)
 		return NULL;
 
-	list_for_each_entry(itte, &device->itt_head, itte_list)
-		if (itte->event_id == event_id)
-			return itte;
+	list_for_each_entry(ite, &device->itt_head, ite_list)
+		if (ite->event_id == event_id)
+			return ite;
 
 	return NULL;
 }
 
 /* To be used as an iterator this macro misses the enclosing parentheses */
-#define for_each_lpi_its(dev, itte, its) \
+#define for_each_lpi_its(dev, ite, its) \
 	list_for_each_entry(dev, &(its)->device_list, dev_list) \
-		list_for_each_entry(itte, &(dev)->itt_head, itte_list)
+		list_for_each_entry(ite, &(dev)->itt_head, ite_list)
 
 /*
  * We only implement 48 bits of PA at the moment, although the ITS
@@ -270,18 +270,18 @@ static int vgic_copy_lpi_list(struct kvm *kvm, u32 **intid_ptr)
  * Needs to be called whenever either the collection for a LPIs has
  * changed or the collection itself got retargeted.
  */
-static void update_affinity_itte(struct kvm *kvm, struct its_itte *itte)
+static void update_affinity_ite(struct kvm *kvm, struct its_ite *ite)
 {
 	struct kvm_vcpu *vcpu;
 
-	if (!its_is_collection_mapped(itte->collection))
+	if (!its_is_collection_mapped(ite->collection))
 		return;
 
-	vcpu = kvm_get_vcpu(kvm, itte->collection->target_addr);
+	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
 
-	spin_lock(&itte->irq->irq_lock);
-	itte->irq->target_vcpu = vcpu;
-	spin_unlock(&itte->irq->irq_lock);
+	spin_lock(&ite->irq->irq_lock);
+	ite->irq->target_vcpu = vcpu;
+	spin_unlock(&ite->irq->irq_lock);
 }
 
 /*
@@ -292,13 +292,13 @@ static void update_affinity_collection(struct kvm *kvm, struct vgic_its *its,
 				       struct its_collection *coll)
 {
 	struct its_device *device;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
-	for_each_lpi_its(device, itte, its) {
-		if (!itte->collection || coll != itte->collection)
+	for_each_lpi_its(device, ite, its) {
+		if (!ite->collection || coll != ite->collection)
 			continue;
 
-		update_affinity_itte(kvm, itte);
+		update_affinity_ite(kvm, ite);
 	}
 }
 
@@ -425,25 +425,25 @@ static int vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
 				u32 devid, u32 eventid)
 {
 	struct kvm_vcpu *vcpu;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 	if (!its->enabled)
 		return -EBUSY;
 
-	itte = find_itte(its, devid, eventid);
-	if (!itte || !its_is_collection_mapped(itte->collection))
+	ite = find_ite(its, devid, eventid);
+	if (!ite || !its_is_collection_mapped(ite->collection))
 		return E_ITS_INT_UNMAPPED_INTERRUPT;
 
-	vcpu = kvm_get_vcpu(kvm, itte->collection->target_addr);
+	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
 	if (!vcpu)
 		return E_ITS_INT_UNMAPPED_INTERRUPT;
 
 	if (!vcpu->arch.vgic_cpu.lpis_enabled)
 		return -EBUSY;
 
-	spin_lock(&itte->irq->irq_lock);
-	itte->irq->pending_latch = true;
-	vgic_queue_irq_unlock(kvm, itte->irq);
+	spin_lock(&ite->irq->irq_lock);
+	ite->irq->pending_latch = true;
+	vgic_queue_irq_unlock(kvm, ite->irq);
 
 	return 0;
 }
@@ -511,15 +511,15 @@ int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
 }
 
 /* Requires the its_lock to be held. */
-static void its_free_itte(struct kvm *kvm, struct its_itte *itte)
+static void its_free_ite(struct kvm *kvm, struct its_ite *ite)
 {
-	list_del(&itte->itte_list);
+	list_del(&ite->ite_list);
 
 	/* This put matches the get in vgic_add_lpi. */
-	if (itte->irq)
-		vgic_put_irq(kvm, itte->irq);
+	if (ite->irq)
+		vgic_put_irq(kvm, ite->irq);
 
-	kfree(itte);
+	kfree(ite);
 }
 
 static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
@@ -544,17 +544,17 @@ static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 
-	itte = find_itte(its, device_id, event_id);
-	if (itte && itte->collection) {
+	ite = find_ite(its, device_id, event_id);
+	if (ite && ite->collection) {
 		/*
 		 * Though the spec talks about removing the pending state, we
 		 * don't bother here since we clear the ITTE anyway and the
 		 * pending state is a property of the ITTE struct.
 		 */
-		its_free_itte(kvm, itte);
+		its_free_ite(kvm, ite);
 		return 0;
 	}
 
@@ -572,26 +572,26 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
 	u32 event_id = its_cmd_get_id(its_cmd);
 	u32 coll_id = its_cmd_get_collection(its_cmd);
 	struct kvm_vcpu *vcpu;
-	struct its_itte *itte;
+	struct its_ite *ite;
 	struct its_collection *collection;
 
-	itte = find_itte(its, device_id, event_id);
-	if (!itte)
+	ite = find_ite(its, device_id, event_id);
+	if (!ite)
 		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
 
-	if (!its_is_collection_mapped(itte->collection))
+	if (!its_is_collection_mapped(ite->collection))
 		return E_ITS_MOVI_UNMAPPED_COLLECTION;
 
 	collection = find_collection(its, coll_id);
 	if (!its_is_collection_mapped(collection))
 		return E_ITS_MOVI_UNMAPPED_COLLECTION;
 
-	itte->collection = collection;
+	ite->collection = collection;
 	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
 
-	spin_lock(&itte->irq->irq_lock);
-	itte->irq->target_vcpu = vcpu;
-	spin_unlock(&itte->irq->irq_lock);
+	spin_lock(&ite->irq->irq_lock);
+	ite->irq->target_vcpu = vcpu;
+	spin_unlock(&ite->irq->irq_lock);
 
 	return 0;
 }
@@ -679,7 +679,7 @@ static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
 {
 	struct its_collection *collection;
 	struct its_device *device;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 	/*
 	 * Clearing the mapping for that collection ID removes the
@@ -690,10 +690,10 @@ static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
 	if (!collection)
 		return;
 
-	for_each_lpi_its(device, itte, its)
-		if (itte->collection &&
-		    itte->collection->collection_id == coll_id)
-			itte->collection = NULL;
+	for_each_lpi_its(device, ite, its)
+		if (ite->collection &&
+		    ite->collection->collection_id == coll_id)
+			ite->collection = NULL;
 
 	list_del(&collection->coll_list);
 	kfree(collection);
@@ -709,7 +709,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
 	u32 coll_id = its_cmd_get_collection(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 	struct its_device *device;
 	struct its_collection *collection, *new_coll = NULL;
 	int lpi_nr;
@@ -728,7 +728,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 		return E_ITS_MAPTI_PHYSICALID_OOR;
 
 	/* If there is an existing mapping, behavior is UNPREDICTABLE. */
-	if (find_itte(its, device_id, event_id))
+	if (find_ite(its, device_id, event_id))
 		return 0;
 
 	collection = find_collection(its, coll_id);
@@ -739,36 +739,36 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 		new_coll = collection;
 	}
 
-	itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
-	if (!itte) {
+	ite = kzalloc(sizeof(struct its_ite), GFP_KERNEL);
+	if (!ite) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
 		return -ENOMEM;
 	}
 
-	itte->event_id	= event_id;
-	list_add_tail(&itte->itte_list, &device->itt_head);
+	ite->event_id	= event_id;
+	list_add_tail(&ite->ite_list, &device->itt_head);
 
-	itte->collection = collection;
-	itte->lpi = lpi_nr;
+	ite->collection = collection;
+	ite->lpi = lpi_nr;
 
 	irq = vgic_add_lpi(kvm, lpi_nr);
 	if (IS_ERR(irq)) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
-		its_free_itte(kvm, itte);
+		its_free_ite(kvm, ite);
 		return PTR_ERR(irq);
 	}
-	itte->irq = irq;
+	ite->irq = irq;
 
-	update_affinity_itte(kvm, itte);
+	update_affinity_ite(kvm, ite);
 
 	/*
 	 * We "cache" the configuration table entries in out struct vgic_irq's.
 	 * However we only have those structs for mapped IRQs, so we read in
 	 * the respective config data from memory here upon mapping the LPI.
 	 */
-	update_lpi_config(kvm, itte->irq, NULL);
+	update_lpi_config(kvm, ite->irq, NULL);
 
 	return 0;
 }
@@ -776,15 +776,15 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 /* Requires the its_lock to be held. */
 static void vgic_its_unmap_device(struct kvm *kvm, struct its_device *device)
 {
-	struct its_itte *itte, *temp;
+	struct its_ite *ite, *temp;
 
 	/*
 	 * The spec says that unmapping a device with still valid
 	 * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
 	 * since we cannot leave the memory unreferenced.
 	 */
-	list_for_each_entry_safe(itte, temp, &device->itt_head, itte_list)
-		its_free_itte(kvm, itte);
+	list_for_each_entry_safe(ite, temp, &device->itt_head, ite_list)
+		its_free_ite(kvm, ite);
 
 	list_del(&device->dev_list);
 	kfree(device);
@@ -883,14 +883,14 @@ static int vgic_its_cmd_handle_clear(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 
-	itte = find_itte(its, device_id, event_id);
-	if (!itte)
+	ite = find_ite(its, device_id, event_id);
+	if (!ite)
 		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
 
-	itte->irq->pending_latch = false;
+	ite->irq->pending_latch = false;
 
 	return 0;
 }
@@ -904,14 +904,14 @@ static int vgic_its_cmd_handle_inv(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 
-	itte = find_itte(its, device_id, event_id);
-	if (!itte)
+	ite = find_ite(its, device_id, event_id);
+	if (!ite)
 		return E_ITS_INV_UNMAPPED_INTERRUPT;
 
-	return update_lpi_config(kvm, itte->irq, NULL);
+	return update_lpi_config(kvm, ite->irq, NULL);
 }
 
 /*
@@ -1435,7 +1435,7 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 	struct kvm *kvm = kvm_dev->kvm;
 	struct vgic_its *its = kvm_dev->private;
 	struct its_device *dev;
-	struct its_itte *itte;
+	struct its_ite *ite;
 	struct list_head *dev_cur, *dev_temp;
 	struct list_head *cur, *temp;
 
@@ -1450,8 +1450,8 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 	list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
 		dev = container_of(dev_cur, struct its_device, dev_list);
 		list_for_each_safe(cur, temp, &dev->itt_head) {
-			itte = (container_of(cur, struct its_itte, itte_list));
-			its_free_itte(kvm, itte);
+			ite = (container_of(cur, struct its_ite, ite_list));
+			its_free_ite(kvm, ite);
 		}
 		list_del(dev_cur);
 		kfree(dev);
-- 
2.5.5

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

* [PATCH v7 03/24] KVM: arm/arm64: vgic-its: rename itte into ite
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

The actual abbreviation for the interrupt translation table entry
is ITE. Let's rename all itte instances by ite.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's A-b

v5: Add Marc's A-b
---
 virt/kvm/arm/vgic/vgic-its.c | 148 +++++++++++++++++++++----------------------
 1 file changed, 74 insertions(+), 74 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 8d1da1a..3ffcbbe 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -114,8 +114,8 @@ struct its_collection {
 #define its_is_collection_mapped(coll) ((coll) && \
 				((coll)->target_addr != COLLECTION_NOT_MAPPED))
 
-struct its_itte {
-	struct list_head itte_list;
+struct its_ite {
+	struct list_head ite_list;
 
 	struct vgic_irq *irq;
 	struct its_collection *collection;
@@ -143,27 +143,27 @@ static struct its_device *find_its_device(struct vgic_its *its, u32 device_id)
  * Device ID/Event ID pair on an ITS.
  * Must be called with the its_lock mutex held.
  */
-static struct its_itte *find_itte(struct vgic_its *its, u32 device_id,
+static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 				  u32 event_id)
 {
 	struct its_device *device;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 	device = find_its_device(its, device_id);
 	if (device == NULL)
 		return NULL;
 
-	list_for_each_entry(itte, &device->itt_head, itte_list)
-		if (itte->event_id == event_id)
-			return itte;
+	list_for_each_entry(ite, &device->itt_head, ite_list)
+		if (ite->event_id == event_id)
+			return ite;
 
 	return NULL;
 }
 
 /* To be used as an iterator this macro misses the enclosing parentheses */
-#define for_each_lpi_its(dev, itte, its) \
+#define for_each_lpi_its(dev, ite, its) \
 	list_for_each_entry(dev, &(its)->device_list, dev_list) \
-		list_for_each_entry(itte, &(dev)->itt_head, itte_list)
+		list_for_each_entry(ite, &(dev)->itt_head, ite_list)
 
 /*
  * We only implement 48 bits of PA at the moment, although the ITS
@@ -270,18 +270,18 @@ static int vgic_copy_lpi_list(struct kvm *kvm, u32 **intid_ptr)
  * Needs to be called whenever either the collection for a LPIs has
  * changed or the collection itself got retargeted.
  */
-static void update_affinity_itte(struct kvm *kvm, struct its_itte *itte)
+static void update_affinity_ite(struct kvm *kvm, struct its_ite *ite)
 {
 	struct kvm_vcpu *vcpu;
 
-	if (!its_is_collection_mapped(itte->collection))
+	if (!its_is_collection_mapped(ite->collection))
 		return;
 
-	vcpu = kvm_get_vcpu(kvm, itte->collection->target_addr);
+	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
 
-	spin_lock(&itte->irq->irq_lock);
-	itte->irq->target_vcpu = vcpu;
-	spin_unlock(&itte->irq->irq_lock);
+	spin_lock(&ite->irq->irq_lock);
+	ite->irq->target_vcpu = vcpu;
+	spin_unlock(&ite->irq->irq_lock);
 }
 
 /*
@@ -292,13 +292,13 @@ static void update_affinity_collection(struct kvm *kvm, struct vgic_its *its,
 				       struct its_collection *coll)
 {
 	struct its_device *device;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
-	for_each_lpi_its(device, itte, its) {
-		if (!itte->collection || coll != itte->collection)
+	for_each_lpi_its(device, ite, its) {
+		if (!ite->collection || coll != ite->collection)
 			continue;
 
-		update_affinity_itte(kvm, itte);
+		update_affinity_ite(kvm, ite);
 	}
 }
 
@@ -425,25 +425,25 @@ static int vgic_its_trigger_msi(struct kvm *kvm, struct vgic_its *its,
 				u32 devid, u32 eventid)
 {
 	struct kvm_vcpu *vcpu;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 	if (!its->enabled)
 		return -EBUSY;
 
-	itte = find_itte(its, devid, eventid);
-	if (!itte || !its_is_collection_mapped(itte->collection))
+	ite = find_ite(its, devid, eventid);
+	if (!ite || !its_is_collection_mapped(ite->collection))
 		return E_ITS_INT_UNMAPPED_INTERRUPT;
 
-	vcpu = kvm_get_vcpu(kvm, itte->collection->target_addr);
+	vcpu = kvm_get_vcpu(kvm, ite->collection->target_addr);
 	if (!vcpu)
 		return E_ITS_INT_UNMAPPED_INTERRUPT;
 
 	if (!vcpu->arch.vgic_cpu.lpis_enabled)
 		return -EBUSY;
 
-	spin_lock(&itte->irq->irq_lock);
-	itte->irq->pending_latch = true;
-	vgic_queue_irq_unlock(kvm, itte->irq);
+	spin_lock(&ite->irq->irq_lock);
+	ite->irq->pending_latch = true;
+	vgic_queue_irq_unlock(kvm, ite->irq);
 
 	return 0;
 }
@@ -511,15 +511,15 @@ int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi)
 }
 
 /* Requires the its_lock to be held. */
-static void its_free_itte(struct kvm *kvm, struct its_itte *itte)
+static void its_free_ite(struct kvm *kvm, struct its_ite *ite)
 {
-	list_del(&itte->itte_list);
+	list_del(&ite->ite_list);
 
 	/* This put matches the get in vgic_add_lpi. */
-	if (itte->irq)
-		vgic_put_irq(kvm, itte->irq);
+	if (ite->irq)
+		vgic_put_irq(kvm, ite->irq);
 
-	kfree(itte);
+	kfree(ite);
 }
 
 static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
@@ -544,17 +544,17 @@ static int vgic_its_cmd_handle_discard(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 
-	itte = find_itte(its, device_id, event_id);
-	if (itte && itte->collection) {
+	ite = find_ite(its, device_id, event_id);
+	if (ite && ite->collection) {
 		/*
 		 * Though the spec talks about removing the pending state, we
 		 * don't bother here since we clear the ITTE anyway and the
 		 * pending state is a property of the ITTE struct.
 		 */
-		its_free_itte(kvm, itte);
+		its_free_ite(kvm, ite);
 		return 0;
 	}
 
@@ -572,26 +572,26 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
 	u32 event_id = its_cmd_get_id(its_cmd);
 	u32 coll_id = its_cmd_get_collection(its_cmd);
 	struct kvm_vcpu *vcpu;
-	struct its_itte *itte;
+	struct its_ite *ite;
 	struct its_collection *collection;
 
-	itte = find_itte(its, device_id, event_id);
-	if (!itte)
+	ite = find_ite(its, device_id, event_id);
+	if (!ite)
 		return E_ITS_MOVI_UNMAPPED_INTERRUPT;
 
-	if (!its_is_collection_mapped(itte->collection))
+	if (!its_is_collection_mapped(ite->collection))
 		return E_ITS_MOVI_UNMAPPED_COLLECTION;
 
 	collection = find_collection(its, coll_id);
 	if (!its_is_collection_mapped(collection))
 		return E_ITS_MOVI_UNMAPPED_COLLECTION;
 
-	itte->collection = collection;
+	ite->collection = collection;
 	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
 
-	spin_lock(&itte->irq->irq_lock);
-	itte->irq->target_vcpu = vcpu;
-	spin_unlock(&itte->irq->irq_lock);
+	spin_lock(&ite->irq->irq_lock);
+	ite->irq->target_vcpu = vcpu;
+	spin_unlock(&ite->irq->irq_lock);
 
 	return 0;
 }
@@ -679,7 +679,7 @@ static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
 {
 	struct its_collection *collection;
 	struct its_device *device;
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 	/*
 	 * Clearing the mapping for that collection ID removes the
@@ -690,10 +690,10 @@ static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
 	if (!collection)
 		return;
 
-	for_each_lpi_its(device, itte, its)
-		if (itte->collection &&
-		    itte->collection->collection_id == coll_id)
-			itte->collection = NULL;
+	for_each_lpi_its(device, ite, its)
+		if (ite->collection &&
+		    ite->collection->collection_id == coll_id)
+			ite->collection = NULL;
 
 	list_del(&collection->coll_list);
 	kfree(collection);
@@ -709,7 +709,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
 	u32 coll_id = its_cmd_get_collection(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 	struct its_device *device;
 	struct its_collection *collection, *new_coll = NULL;
 	int lpi_nr;
@@ -728,7 +728,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 		return E_ITS_MAPTI_PHYSICALID_OOR;
 
 	/* If there is an existing mapping, behavior is UNPREDICTABLE. */
-	if (find_itte(its, device_id, event_id))
+	if (find_ite(its, device_id, event_id))
 		return 0;
 
 	collection = find_collection(its, coll_id);
@@ -739,36 +739,36 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 		new_coll = collection;
 	}
 
-	itte = kzalloc(sizeof(struct its_itte), GFP_KERNEL);
-	if (!itte) {
+	ite = kzalloc(sizeof(struct its_ite), GFP_KERNEL);
+	if (!ite) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
 		return -ENOMEM;
 	}
 
-	itte->event_id	= event_id;
-	list_add_tail(&itte->itte_list, &device->itt_head);
+	ite->event_id	= event_id;
+	list_add_tail(&ite->ite_list, &device->itt_head);
 
-	itte->collection = collection;
-	itte->lpi = lpi_nr;
+	ite->collection = collection;
+	ite->lpi = lpi_nr;
 
 	irq = vgic_add_lpi(kvm, lpi_nr);
 	if (IS_ERR(irq)) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
-		its_free_itte(kvm, itte);
+		its_free_ite(kvm, ite);
 		return PTR_ERR(irq);
 	}
-	itte->irq = irq;
+	ite->irq = irq;
 
-	update_affinity_itte(kvm, itte);
+	update_affinity_ite(kvm, ite);
 
 	/*
 	 * We "cache" the configuration table entries in out struct vgic_irq's.
 	 * However we only have those structs for mapped IRQs, so we read in
 	 * the respective config data from memory here upon mapping the LPI.
 	 */
-	update_lpi_config(kvm, itte->irq, NULL);
+	update_lpi_config(kvm, ite->irq, NULL);
 
 	return 0;
 }
@@ -776,15 +776,15 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 /* Requires the its_lock to be held. */
 static void vgic_its_unmap_device(struct kvm *kvm, struct its_device *device)
 {
-	struct its_itte *itte, *temp;
+	struct its_ite *ite, *temp;
 
 	/*
 	 * The spec says that unmapping a device with still valid
 	 * ITTEs associated is UNPREDICTABLE. We remove all ITTEs,
 	 * since we cannot leave the memory unreferenced.
 	 */
-	list_for_each_entry_safe(itte, temp, &device->itt_head, itte_list)
-		its_free_itte(kvm, itte);
+	list_for_each_entry_safe(ite, temp, &device->itt_head, ite_list)
+		its_free_ite(kvm, ite);
 
 	list_del(&device->dev_list);
 	kfree(device);
@@ -883,14 +883,14 @@ static int vgic_its_cmd_handle_clear(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 
-	itte = find_itte(its, device_id, event_id);
-	if (!itte)
+	ite = find_ite(its, device_id, event_id);
+	if (!ite)
 		return E_ITS_CLEAR_UNMAPPED_INTERRUPT;
 
-	itte->irq->pending_latch = false;
+	ite->irq->pending_latch = false;
 
 	return 0;
 }
@@ -904,14 +904,14 @@ static int vgic_its_cmd_handle_inv(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	u32 event_id = its_cmd_get_id(its_cmd);
-	struct its_itte *itte;
+	struct its_ite *ite;
 
 
-	itte = find_itte(its, device_id, event_id);
-	if (!itte)
+	ite = find_ite(its, device_id, event_id);
+	if (!ite)
 		return E_ITS_INV_UNMAPPED_INTERRUPT;
 
-	return update_lpi_config(kvm, itte->irq, NULL);
+	return update_lpi_config(kvm, ite->irq, NULL);
 }
 
 /*
@@ -1435,7 +1435,7 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 	struct kvm *kvm = kvm_dev->kvm;
 	struct vgic_its *its = kvm_dev->private;
 	struct its_device *dev;
-	struct its_itte *itte;
+	struct its_ite *ite;
 	struct list_head *dev_cur, *dev_temp;
 	struct list_head *cur, *temp;
 
@@ -1450,8 +1450,8 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 	list_for_each_safe(dev_cur, dev_temp, &its->device_list) {
 		dev = container_of(dev_cur, struct its_device, dev_list);
 		list_for_each_safe(cur, temp, &dev->itt_head) {
-			itte = (container_of(cur, struct its_itte, itte_list));
-			its_free_itte(kvm, itte);
+			ite = (container_of(cur, struct its_ite, ite_list));
+			its_free_ite(kvm, ite);
 		}
 		list_del(dev_cur);
 		kfree(dev);
-- 
2.5.5

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

* [PATCH v7 04/24] arm/arm64: vgic: turn vgic_find_mmio_region into public
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

We plan to use vgic_find_mmio_region in vgic-its.c so let's
turn it into a public function.

Also let's take the opportunity to rename the region parameter
into regions to emphasize this latter is an array of regions.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v5 -> v6:
- add Christoffer's A-b

v4 -> v5:
- add Marc's A-b

v3 -> v4:
- rename region parameter into regions
- add Andre's R-b
---
 virt/kvm/arm/vgic/vgic-mmio.c | 11 +++++------
 virt/kvm/arm/vgic/vgic-mmio.h |  5 +++++
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 2a5db13..1c17b2a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -446,13 +446,12 @@ static int match_region(const void *key, const void *elt)
 	return 0;
 }
 
-/* Find the proper register handler entry given a certain address offset. */
-static const struct vgic_register_region *
-vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
-		      unsigned int offset)
+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, region, nr_regions,
-		       sizeof(region[0]), match_region);
+	return bsearch((void *)(uintptr_t)offset, regions, nr_regions,
+		       sizeof(regions[0]), match_region);
 }
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 98bb566..6eec91b 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -192,4 +192,9 @@ u64 vgic_sanitise_shareability(u64 reg);
 u64 vgic_sanitise_field(u64 reg, u64 field_mask, int field_shift,
 			u64 (*sanitise_fn)(u64));
 
+/* Find the proper register handler entry given a certain address offset */
+const struct vgic_register_region *
+vgic_find_mmio_region(const struct vgic_register_region *regions,
+		      int nr_regions, unsigned int offset);
+
 #endif
-- 
2.5.5

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

* [PATCH v7 04/24] arm/arm64: vgic: turn vgic_find_mmio_region into public
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

We plan to use vgic_find_mmio_region in vgic-its.c so let's
turn it into a public function.

Also let's take the opportunity to rename the region parameter
into regions to emphasize this latter is an array of regions.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v5 -> v6:
- add Christoffer's A-b

v4 -> v5:
- add Marc's A-b

v3 -> v4:
- rename region parameter into regions
- add Andre's R-b
---
 virt/kvm/arm/vgic/vgic-mmio.c | 11 +++++------
 virt/kvm/arm/vgic/vgic-mmio.h |  5 +++++
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 2a5db13..1c17b2a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -446,13 +446,12 @@ static int match_region(const void *key, const void *elt)
 	return 0;
 }
 
-/* Find the proper register handler entry given a certain address offset. */
-static const struct vgic_register_region *
-vgic_find_mmio_region(const struct vgic_register_region *region, int nr_regions,
-		      unsigned int offset)
+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, region, nr_regions,
-		       sizeof(region[0]), match_region);
+	return bsearch((void *)(uintptr_t)offset, regions, nr_regions,
+		       sizeof(regions[0]), match_region);
 }
 
 void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 98bb566..6eec91b 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -192,4 +192,9 @@ u64 vgic_sanitise_shareability(u64 reg);
 u64 vgic_sanitise_field(u64 reg, u64 field_mask, int field_shift,
 			u64 (*sanitise_fn)(u64));
 
+/* Find the proper register handler entry given a certain address offset */
+const struct vgic_register_region *
+vgic_find_mmio_region(const struct vgic_register_region *regions,
+		      int nr_regions, unsigned int offset);
+
 #endif
-- 
2.5.5

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

* [PATCH v7 05/24] KVM: arm64: vgic-its: KVM_DEV_ARM_VGIC_GRP_ITS_REGS group
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

The ITS KVM device exposes a new KVM_DEV_ARM_VGIC_GRP_ITS_REGS
group which allows the userspace to save/restore ITS registers.

At this stage the get/set/has operations are not yet implemented.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>

---
v5 -> v6:
- Add Christoffer's R-b

v4 -> v5:
- Add Marc's A-b

v3 -> v4:
- added Andre's R-b
---
 arch/arm/include/uapi/asm/kvm.h   |  1 +
 arch/arm64/include/uapi/asm/kvm.h |  1 +
 virt/kvm/arm/vgic/vgic-its.c      | 36 +++++++++++++++++++++++++++++++++++-
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 6ebd3e6..4beb83b 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -192,6 +192,7 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO  7
+#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS	8
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
 			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index c286035..7e8dd69 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -212,6 +212,7 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO  7
+#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
 			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 3ffcbbe..f687e91 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1466,6 +1466,19 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 	kfree(its);
 }
 
+int vgic_its_has_attr_regs(struct kvm_device *dev,
+			   struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+int vgic_its_attr_regs_access(struct kvm_device *dev,
+			      struct kvm_device_attr *attr,
+			      u64 *reg, bool is_write)
+{
+	return -ENXIO;
+}
+
 static int vgic_its_has_attr(struct kvm_device *dev,
 			     struct kvm_device_attr *attr)
 {
@@ -1482,6 +1495,8 @@ static int vgic_its_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
+		return vgic_its_has_attr_regs(dev, attr);
 	}
 	return -ENXIO;
 }
@@ -1521,6 +1536,15 @@ static int vgic_its_set_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
+
+		return vgic_its_attr_regs_access(dev, attr, &reg, true);
+	}
 	}
 	return -ENXIO;
 }
@@ -1541,10 +1565,20 @@ static int vgic_its_get_attr(struct kvm_device *dev,
 		if (copy_to_user(uaddr, &addr, sizeof(addr)))
 			return -EFAULT;
 		break;
+	}
+	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+		int ret;
+
+		ret = vgic_its_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
 	default:
 		return -ENXIO;
 	}
-	}
 
 	return 0;
 }
-- 
2.5.5

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

* [PATCH v7 05/24] KVM: arm64: vgic-its: KVM_DEV_ARM_VGIC_GRP_ITS_REGS group
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

The ITS KVM device exposes a new KVM_DEV_ARM_VGIC_GRP_ITS_REGS
group which allows the userspace to save/restore ITS registers.

At this stage the get/set/has operations are not yet implemented.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>

---
v5 -> v6:
- Add Christoffer's R-b

v4 -> v5:
- Add Marc's A-b

v3 -> v4:
- added Andre's R-b
---
 arch/arm/include/uapi/asm/kvm.h   |  1 +
 arch/arm64/include/uapi/asm/kvm.h |  1 +
 virt/kvm/arm/vgic/vgic-its.c      | 36 +++++++++++++++++++++++++++++++++++-
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 6ebd3e6..4beb83b 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -192,6 +192,7 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO  7
+#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS	8
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
 			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index c286035..7e8dd69 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -212,6 +212,7 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_REDIST_REGS 5
 #define KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS 6
 #define KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO  7
+#define KVM_DEV_ARM_VGIC_GRP_ITS_REGS 8
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT	10
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK \
 			(0x3fffffULL << KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 3ffcbbe..f687e91 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1466,6 +1466,19 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 	kfree(its);
 }
 
+int vgic_its_has_attr_regs(struct kvm_device *dev,
+			   struct kvm_device_attr *attr)
+{
+	return -ENXIO;
+}
+
+int vgic_its_attr_regs_access(struct kvm_device *dev,
+			      struct kvm_device_attr *attr,
+			      u64 *reg, bool is_write)
+{
+	return -ENXIO;
+}
+
 static int vgic_its_has_attr(struct kvm_device *dev,
 			     struct kvm_device_attr *attr)
 {
@@ -1482,6 +1495,8 @@ static int vgic_its_has_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
+		return vgic_its_has_attr_regs(dev, attr);
 	}
 	return -ENXIO;
 }
@@ -1521,6 +1536,15 @@ static int vgic_its_set_attr(struct kvm_device *dev,
 			return 0;
 		}
 		break;
+	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
+
+		return vgic_its_attr_regs_access(dev, attr, &reg, true);
+	}
 	}
 	return -ENXIO;
 }
@@ -1541,10 +1565,20 @@ static int vgic_its_get_attr(struct kvm_device *dev,
 		if (copy_to_user(uaddr, &addr, sizeof(addr)))
 			return -EFAULT;
 		break;
+	}
+	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
+		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
+		u64 reg;
+		int ret;
+
+		ret = vgic_its_attr_regs_access(dev, attr, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
 	default:
 		return -ENXIO;
 	}
-	}
 
 	return 0;
 }
-- 
2.5.5

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

* [PATCH v7 06/24] KVM: arm/arm64: vgic: expose (un)lock_all_vcpus
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

We need to use those helpers in vgic-its.c so let's
expose them in the private vgic header.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v5 -> v6:
- Add Christoffer's A-b

v4 -> v5:
- Add Marc's A-b
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 4 ++--
 virt/kvm/arm/vgic/vgic.h            | 3 +++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index d181d2b..859bfa8 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -259,13 +259,13 @@ static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx)
 	}
 }
 
-static void unlock_all_vcpus(struct kvm *kvm)
+void unlock_all_vcpus(struct kvm *kvm)
 {
 	unlock_vcpus(kvm, atomic_read(&kvm->online_vcpus) - 1);
 }
 
 /* Returns true if all vcpus were locked, false otherwise */
-static bool lock_all_vcpus(struct kvm *kvm)
+bool lock_all_vcpus(struct kvm *kvm)
 {
 	struct kvm_vcpu *tmp_vcpu;
 	int c;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 6cf557e..b87f1c6 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -184,4 +184,7 @@ int vgic_init(struct kvm *kvm);
 int vgic_debug_init(struct kvm *kvm);
 int vgic_debug_destroy(struct kvm *kvm);
 
+bool lock_all_vcpus(struct kvm *kvm);
+void unlock_all_vcpus(struct kvm *kvm);
+
 #endif
-- 
2.5.5

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

* [PATCH v7 06/24] KVM: arm/arm64: vgic: expose (un)lock_all_vcpus
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

We need to use those helpers in vgic-its.c so let's
expose them in the private vgic header.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v5 -> v6:
- Add Christoffer's A-b

v4 -> v5:
- Add Marc's A-b
---
 virt/kvm/arm/vgic/vgic-kvm-device.c | 4 ++--
 virt/kvm/arm/vgic/vgic.h            | 3 +++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index d181d2b..859bfa8 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -259,13 +259,13 @@ static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx)
 	}
 }
 
-static void unlock_all_vcpus(struct kvm *kvm)
+void unlock_all_vcpus(struct kvm *kvm)
 {
 	unlock_vcpus(kvm, atomic_read(&kvm->online_vcpus) - 1);
 }
 
 /* Returns true if all vcpus were locked, false otherwise */
-static bool lock_all_vcpus(struct kvm *kvm)
+bool lock_all_vcpus(struct kvm *kvm)
 {
 	struct kvm_vcpu *tmp_vcpu;
 	int c;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 6cf557e..b87f1c6 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -184,4 +184,7 @@ int vgic_init(struct kvm *kvm);
 int vgic_debug_init(struct kvm *kvm);
 int vgic_debug_destroy(struct kvm *kvm);
 
+bool lock_all_vcpus(struct kvm *kvm);
+void unlock_all_vcpus(struct kvm *kvm);
+
 #endif
-- 
2.5.5

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

* [PATCH v7 07/24] KVM: arm64: vgic-its: Implement vgic_its_has_attr_regs and attr_regs_access
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

This patch implements vgic_its_has_attr_regs and vgic_its_attr_regs_access
upon the MMIO framework. VGIC ITS KVM device KVM_DEV_ARM_VGIC_GRP_ITS_REGS
group becomes functional.

At least GITS_CREADR and GITS_IIDR require to differentiate a guest write
action from a user access. As such let's introduce a new uaccess_its_write
vgic_register_region callback.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- check alignment of the offset also on vgic_its_has_attr_regs
- remote ternary conditional on align assignment
- add Christoffer's R-b

v5 -> v6:
- fix GITS_PIDR/CIDR accesses
- remove vgic_data_mmio_bus_to_host/vgic_data_host_to_mmio_bus
- 64b full reg access comment rewording
- vgic_its_attr_regs_access declaration block rework including
  removal of iodev

v4 -> v5:
- use GITS_TYPER instead of offset 0x8
- uaccess_its_write now can return an error

v3 -> v4:
- remove changes to the REGISTER_ITS_DESC macro. This will be handled in
  subsequent patch with the introduction of a new REGISTER_ITS_DESC_UACCESS
  macro
- fix IIDR access and add a comment wrt full length access
- handle endianness
- add kvm lock and vcpus lock
---
 virt/kvm/arm/vgic/vgic-its.c  | 79 +++++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio.h |  9 +++--
 2 files changed, 84 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index f687e91..fd2660d 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1469,14 +1469,89 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 int vgic_its_has_attr_regs(struct kvm_device *dev,
 			   struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	const struct vgic_register_region *region;
+	gpa_t offset = attr->attr;
+	int align;
+
+	align = (offset < GITS_TYPER) || (offset >= GITS_PIDR4) ? 0x3 : 0x7;
+
+	if (offset & align)
+		return -EINVAL;
+
+	region = vgic_find_mmio_region(its_registers,
+				       ARRAY_SIZE(its_registers),
+				       offset);
+	if (!region)
+		return -ENXIO;
+
+	return 0;
 }
 
 int vgic_its_attr_regs_access(struct kvm_device *dev,
 			      struct kvm_device_attr *attr,
 			      u64 *reg, bool is_write)
 {
-	return -ENXIO;
+	const struct vgic_register_region *region;
+	struct vgic_its *its;
+	gpa_t addr, offset;
+	unsigned int len;
+	int align, ret = 0;
+
+	its = dev->private;
+	offset = attr->attr;
+
+	/*
+	 * Although the spec supports upper/lower 32-bit accesses to
+	 * 64-bit ITS registers, the userspace ABI requires 64-bit
+	 * accesses to all 64-bit wide registers. We therefore only
+	 * support 32-bit accesses to GITS_CTLR, GITS_IIDR and GITS ID
+	 * registers
+	 */
+	if ((offset < GITS_TYPER) || (offset >= GITS_PIDR4))
+		align = 0x3;
+	else
+		align = 0x7;
+
+	if (offset & align)
+		return -EINVAL;
+
+	mutex_lock(&dev->kvm->lock);
+
+	if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	region = vgic_find_mmio_region(its_registers,
+				       ARRAY_SIZE(its_registers),
+				       offset);
+	if (!region) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (!lock_all_vcpus(dev->kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	addr = its->vgic_its_base + offset;
+
+	len = region->access_flags & VGIC_ACCESS_64bit ? 8 : 4;
+
+	if (is_write) {
+		if (region->uaccess_its_write)
+			ret = region->uaccess_its_write(dev->kvm, its, addr,
+							len, *reg);
+		else
+			region->its_write(dev->kvm, its, addr, len, *reg);
+	} else {
+		*reg = region->its_read(dev->kvm, its, addr, len);
+	}
+	unlock_all_vcpus(dev->kvm);
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
 }
 
 static int vgic_its_has_attr(struct kvm_device *dev,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 6eec91b..ea4171a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -36,8 +36,13 @@ struct vgic_register_region {
 	};
 	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
 				      unsigned int len);
-	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
-			      unsigned int len, unsigned long val);
+	union {
+		void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
+				      unsigned int len, unsigned long val);
+		int (*uaccess_its_write)(struct kvm *kvm, struct vgic_its *its,
+					 gpa_t addr, unsigned int len,
+					 unsigned long val);
+	};
 };
 
 extern struct kvm_io_device_ops kvm_io_gic_ops;
-- 
2.5.5

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

* [PATCH v7 07/24] KVM: arm64: vgic-its: Implement vgic_its_has_attr_regs and attr_regs_access
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implements vgic_its_has_attr_regs and vgic_its_attr_regs_access
upon the MMIO framework. VGIC ITS KVM device KVM_DEV_ARM_VGIC_GRP_ITS_REGS
group becomes functional.

At least GITS_CREADR and GITS_IIDR require to differentiate a guest write
action from a user access. As such let's introduce a new uaccess_its_write
vgic_register_region callback.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- check alignment of the offset also on vgic_its_has_attr_regs
- remote ternary conditional on align assignment
- add Christoffer's R-b

v5 -> v6:
- fix GITS_PIDR/CIDR accesses
- remove vgic_data_mmio_bus_to_host/vgic_data_host_to_mmio_bus
- 64b full reg access comment rewording
- vgic_its_attr_regs_access declaration block rework including
  removal of iodev

v4 -> v5:
- use GITS_TYPER instead of offset 0x8
- uaccess_its_write now can return an error

v3 -> v4:
- remove changes to the REGISTER_ITS_DESC macro. This will be handled in
  subsequent patch with the introduction of a new REGISTER_ITS_DESC_UACCESS
  macro
- fix IIDR access and add a comment wrt full length access
- handle endianness
- add kvm lock and vcpus lock
---
 virt/kvm/arm/vgic/vgic-its.c  | 79 +++++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic-mmio.h |  9 +++--
 2 files changed, 84 insertions(+), 4 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index f687e91..fd2660d 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1469,14 +1469,89 @@ static void vgic_its_destroy(struct kvm_device *kvm_dev)
 int vgic_its_has_attr_regs(struct kvm_device *dev,
 			   struct kvm_device_attr *attr)
 {
-	return -ENXIO;
+	const struct vgic_register_region *region;
+	gpa_t offset = attr->attr;
+	int align;
+
+	align = (offset < GITS_TYPER) || (offset >= GITS_PIDR4) ? 0x3 : 0x7;
+
+	if (offset & align)
+		return -EINVAL;
+
+	region = vgic_find_mmio_region(its_registers,
+				       ARRAY_SIZE(its_registers),
+				       offset);
+	if (!region)
+		return -ENXIO;
+
+	return 0;
 }
 
 int vgic_its_attr_regs_access(struct kvm_device *dev,
 			      struct kvm_device_attr *attr,
 			      u64 *reg, bool is_write)
 {
-	return -ENXIO;
+	const struct vgic_register_region *region;
+	struct vgic_its *its;
+	gpa_t addr, offset;
+	unsigned int len;
+	int align, ret = 0;
+
+	its = dev->private;
+	offset = attr->attr;
+
+	/*
+	 * Although the spec supports upper/lower 32-bit accesses to
+	 * 64-bit ITS registers, the userspace ABI requires 64-bit
+	 * accesses to all 64-bit wide registers. We therefore only
+	 * support 32-bit accesses to GITS_CTLR, GITS_IIDR and GITS ID
+	 * registers
+	 */
+	if ((offset < GITS_TYPER) || (offset >= GITS_PIDR4))
+		align = 0x3;
+	else
+		align = 0x7;
+
+	if (offset & align)
+		return -EINVAL;
+
+	mutex_lock(&dev->kvm->lock);
+
+	if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	region = vgic_find_mmio_region(its_registers,
+				       ARRAY_SIZE(its_registers),
+				       offset);
+	if (!region) {
+		ret = -ENXIO;
+		goto out;
+	}
+
+	if (!lock_all_vcpus(dev->kvm)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	addr = its->vgic_its_base + offset;
+
+	len = region->access_flags & VGIC_ACCESS_64bit ? 8 : 4;
+
+	if (is_write) {
+		if (region->uaccess_its_write)
+			ret = region->uaccess_its_write(dev->kvm, its, addr,
+							len, *reg);
+		else
+			region->its_write(dev->kvm, its, addr, len, *reg);
+	} else {
+		*reg = region->its_read(dev->kvm, its, addr, len);
+	}
+	unlock_all_vcpus(dev->kvm);
+out:
+	mutex_unlock(&dev->kvm->lock);
+	return ret;
 }
 
 static int vgic_its_has_attr(struct kvm_device *dev,
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 6eec91b..ea4171a 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -36,8 +36,13 @@ struct vgic_register_region {
 	};
 	unsigned long (*uaccess_read)(struct kvm_vcpu *vcpu, gpa_t addr,
 				      unsigned int len);
-	void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
-			      unsigned int len, unsigned long val);
+	union {
+		void (*uaccess_write)(struct kvm_vcpu *vcpu, gpa_t addr,
+				      unsigned int len, unsigned long val);
+		int (*uaccess_its_write)(struct kvm *kvm, struct vgic_its *its,
+					 gpa_t addr, unsigned int len,
+					 unsigned long val);
+	};
 };
 
 extern struct kvm_io_device_ops kvm_io_gic_ops;
-- 
2.5.5

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

* [PATCH v7 08/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_creadr
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

GITS_CREADR needs to be restored so let's implement the associated
uaccess_write_its callback. The write only is allowed if the its
is disabled.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Marc's A-b
- discard the stalled bit if set
- remove the alignment check as cmd_offset is [19:5] of the offset
  and bits [4:0] are 0
- added Christoffer R-b

v5 -> v6:
- remove usage of update_64bit_reg and check alignment of cmd offset

v4 -> v5:
- keep Stalled bit
- vgic_mmio_uaccess_write_its_creadr can now return an error

v3 -> v4:
- REGISTER_ITS_DESC_UACCESS now introduced in this patch
- we now check the its is disabled
---
 virt/kvm/arm/vgic/vgic-its.c | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index fd2660d..bf3ff09 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1213,6 +1213,33 @@ static unsigned long vgic_mmio_read_its_creadr(struct kvm *kvm,
 	return extract_bytes(its->creadr, addr & 0x7, len);
 }
 
+static int vgic_mmio_uaccess_write_its_creadr(struct kvm *kvm,
+					      struct vgic_its *its,
+					      gpa_t addr, unsigned int len,
+					      unsigned long val)
+{
+	u32 cmd_offset;
+	int ret = 0;
+
+	mutex_lock(&its->cmd_lock);
+
+	if (its->enabled) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	cmd_offset = ITS_CMD_OFFSET(val);
+	if (cmd_offset >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	its->creadr = cmd_offset;
+out:
+	mutex_unlock(&its->cmd_lock);
+	return ret;
+}
+
 #define BASER_INDEX(addr) (((addr) / sizeof(u64)) & 0x7)
 static unsigned long vgic_mmio_read_its_baser(struct kvm *kvm,
 					      struct vgic_its *its,
@@ -1317,6 +1344,16 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
 	.its_write = wr,					\
 }
 
+#define REGISTER_ITS_DESC_UACCESS(off, rd, wr, uwr, length, acc)\
+{								\
+	.reg_offset = off,					\
+	.len = length,						\
+	.access_flags = acc,					\
+	.its_read = rd,						\
+	.its_write = wr,					\
+	.uaccess_its_write = uwr,				\
+}
+
 static void its_mmio_write_wi(struct kvm *kvm, struct vgic_its *its,
 			      gpa_t addr, unsigned int len, unsigned long val)
 {
@@ -1339,8 +1376,9 @@ static struct vgic_register_region its_registers[] = {
 	REGISTER_ITS_DESC(GITS_CWRITER,
 		vgic_mmio_read_its_cwriter, vgic_mmio_write_its_cwriter, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
-	REGISTER_ITS_DESC(GITS_CREADR,
-		vgic_mmio_read_its_creadr, its_mmio_write_wi, 8,
+	REGISTER_ITS_DESC_UACCESS(GITS_CREADR,
+		vgic_mmio_read_its_creadr, its_mmio_write_wi,
+		vgic_mmio_uaccess_write_its_creadr, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
 	REGISTER_ITS_DESC(GITS_BASER,
 		vgic_mmio_read_its_baser, vgic_mmio_write_its_baser, 0x40,
-- 
2.5.5

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

* [PATCH v7 08/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_creadr
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

GITS_CREADR needs to be restored so let's implement the associated
uaccess_write_its callback. The write only is allowed if the its
is disabled.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Marc's A-b
- discard the stalled bit if set
- remove the alignment check as cmd_offset is [19:5] of the offset
  and bits [4:0] are 0
- added Christoffer R-b

v5 -> v6:
- remove usage of update_64bit_reg and check alignment of cmd offset

v4 -> v5:
- keep Stalled bit
- vgic_mmio_uaccess_write_its_creadr can now return an error

v3 -> v4:
- REGISTER_ITS_DESC_UACCESS now introduced in this patch
- we now check the its is disabled
---
 virt/kvm/arm/vgic/vgic-its.c | 42 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index fd2660d..bf3ff09 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1213,6 +1213,33 @@ static unsigned long vgic_mmio_read_its_creadr(struct kvm *kvm,
 	return extract_bytes(its->creadr, addr & 0x7, len);
 }
 
+static int vgic_mmio_uaccess_write_its_creadr(struct kvm *kvm,
+					      struct vgic_its *its,
+					      gpa_t addr, unsigned int len,
+					      unsigned long val)
+{
+	u32 cmd_offset;
+	int ret = 0;
+
+	mutex_lock(&its->cmd_lock);
+
+	if (its->enabled) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	cmd_offset = ITS_CMD_OFFSET(val);
+	if (cmd_offset >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	its->creadr = cmd_offset;
+out:
+	mutex_unlock(&its->cmd_lock);
+	return ret;
+}
+
 #define BASER_INDEX(addr) (((addr) / sizeof(u64)) & 0x7)
 static unsigned long vgic_mmio_read_its_baser(struct kvm *kvm,
 					      struct vgic_its *its,
@@ -1317,6 +1344,16 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
 	.its_write = wr,					\
 }
 
+#define REGISTER_ITS_DESC_UACCESS(off, rd, wr, uwr, length, acc)\
+{								\
+	.reg_offset = off,					\
+	.len = length,						\
+	.access_flags = acc,					\
+	.its_read = rd,						\
+	.its_write = wr,					\
+	.uaccess_its_write = uwr,				\
+}
+
 static void its_mmio_write_wi(struct kvm *kvm, struct vgic_its *its,
 			      gpa_t addr, unsigned int len, unsigned long val)
 {
@@ -1339,8 +1376,9 @@ static struct vgic_register_region its_registers[] = {
 	REGISTER_ITS_DESC(GITS_CWRITER,
 		vgic_mmio_read_its_cwriter, vgic_mmio_write_its_cwriter, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
-	REGISTER_ITS_DESC(GITS_CREADR,
-		vgic_mmio_read_its_creadr, its_mmio_write_wi, 8,
+	REGISTER_ITS_DESC_UACCESS(GITS_CREADR,
+		vgic_mmio_read_its_creadr, its_mmio_write_wi,
+		vgic_mmio_uaccess_write_its_creadr, 8,
 		VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
 	REGISTER_ITS_DESC(GITS_BASER,
 		vgic_mmio_read_its_baser, vgic_mmio_write_its_baser, 0x40,
-- 
2.5.5

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

* [PATCH v7 09/24] KVM: arm64: vgic-its: Introduce migration ABI infrastructure
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

We plan to support different migration ABIs, ie. characterizing
the ITS table layout format in guest RAM. For example, a new ABI
will be needed if vLPIs get supported for nested use case.

So let's introduce an array of supported ABIs (at the moment a single
ABI is supported though). The following characteristics are foreseen
to vary with the ABI: size of table entries, save/restore operation,
the way abi settings are applied.

By default the MAX_ABI_REV is applied on its creation. In subsequent
patches we will introduce a way for the userspace to change the ABI
in use.

The entry sizes now are set according to the ABI version and not
hardcoded anymore.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- define and use NR_ITS_ABIS
- reword kernel doc comment of @commit

v5 -> v6:
- rename abi into its_table_abi_versions
- kernel doc comments for struct vgic_its_abi
- comment GIC_ENCODE_SZ
- slighly rephrase the commit message

v5: creation and squash KVM: arm64: ITS: Report the ITE size in
    GITS_TYPER
---
 include/kvm/arm_vgic.h             |  3 ++
 include/linux/irqchip/arm-gic-v3.h |  5 ++
 virt/kvm/arm/vgic/vgic-its.c       | 93 ++++++++++++++++++++++++++++++++++++--
 3 files changed, 97 insertions(+), 4 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c0b3d99..285474a 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -162,6 +162,9 @@ struct vgic_its {
 	u32			creadr;
 	u32			cwriter;
 
+	/* migration ABI revision in use */
+	u32			abi_rev;
+
 	/* Protects the device and collection lists */
 	struct mutex		its_lock;
 	struct list_head	device_list;
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 97cbca1..81ebe43 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -132,6 +132,9 @@
 #define GIC_BASER_SHAREABILITY(reg, type)				\
 	(GIC_BASER_##type << reg##_SHAREABILITY_SHIFT)
 
+/* encode a size field of width @w containing @n - 1 units */
+#define GIC_ENCODE_SZ(n, w) (((unsigned long)(n) - 1) & GENMASK_ULL(((w) - 1), 0))
+
 #define GICR_PROPBASER_SHAREABILITY_SHIFT		(10)
 #define GICR_PROPBASER_INNER_CACHEABILITY_SHIFT		(7)
 #define GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT		(56)
@@ -232,6 +235,7 @@
 #define GITS_CTLR_QUIESCENT		(1U << 31)
 
 #define GITS_TYPER_PLPIS		(1UL << 0)
+#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT	4
 #define GITS_TYPER_IDBITS_SHIFT		8
 #define GITS_TYPER_DEVBITS_SHIFT	13
 #define GITS_TYPER_DEVBITS(r)		((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
@@ -290,6 +294,7 @@
 #define GITS_BASER_TYPE(r)		(((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT		(48)
 #define GITS_BASER_ENTRY_SIZE(r)	((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
+#define GITS_BASER_ENTRY_SIZE_MASK	GENMASK_ULL(52, 48)
 #define GITS_BASER_SHAREABILITY_SHIFT	(10)
 #define GITS_BASER_InnerShareable					\
 	GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index bf3ff09..4f6ea46 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -33,6 +33,10 @@
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static int vgic_its_save_tables_v0(struct vgic_its *its);
+static int vgic_its_restore_tables_v0(struct vgic_its *its);
+static int vgic_its_commit_v0(struct vgic_its *its);
+
 /*
  * Creates a new (reference to a) struct vgic_irq for a given LPI.
  * If this LPI is already mapped on another ITS, we increase its refcount
@@ -123,6 +127,50 @@ struct its_ite {
 	u32 event_id;
 };
 
+/**
+ * struct vgic_its_abi - ITS abi ops and settings
+ * @cte_esz: collection table entry size
+ * @dte_esz: device table entry size
+ * @ite_esz: interrupt translation table entry size
+ * @save tables: save the ITS tables into guest RAM
+ * @restore_tables: restore the ITS internal structs from tables
+ *  stored in guest RAM
+ * @commit: initialize the registers which expose the ABI settings,
+ *  especially the entry sizes
+ */
+struct vgic_its_abi {
+	int cte_esz;
+	int dte_esz;
+	int ite_esz;
+	int (*save_tables)(struct vgic_its *its);
+	int (*restore_tables)(struct vgic_its *its);
+	int (*commit)(struct vgic_its *its);
+};
+
+static const struct vgic_its_abi its_table_abi_versions[] = {
+	[0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
+	 .save_tables = vgic_its_save_tables_v0,
+	 .restore_tables = vgic_its_restore_tables_v0,
+	 .commit = vgic_its_commit_v0,
+	},
+};
+
+#define NR_ITS_ABIS	ARRAY_SIZE(its_table_abi_versions)
+
+inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
+{
+	return &its_table_abi_versions[its->abi_rev];
+}
+
+int vgic_its_set_abi(struct vgic_its *its, int rev)
+{
+	const struct vgic_its_abi *abi;
+
+	its->abi_rev = rev;
+	abi = vgic_its_get_abi(its);
+	return abi->commit(its);
+}
+
 /*
  * Find and returns a device in the device table for an ITS.
  * Must be called with the its_lock mutex held.
@@ -364,6 +412,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 					      struct vgic_its *its,
 					      gpa_t addr, unsigned int len)
 {
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
 	u64 reg = GITS_TYPER_PLPIS;
 
 	/*
@@ -376,6 +425,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 	 */
 	reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
 	reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
+	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
 
 	return extract_bytes(reg, addr & 7, len);
 }
@@ -1268,6 +1318,7 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 				      gpa_t addr, unsigned int len,
 				      unsigned long val)
 {
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
 	u64 entry_size, device_type;
 	u64 reg, *regptr, clearbits = 0;
 
@@ -1278,12 +1329,12 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 	switch (BASER_INDEX(addr)) {
 	case 0:
 		regptr = &its->baser_device_table;
-		entry_size = 8;
+		entry_size = abi->dte_esz;
 		device_type = GITS_BASER_TYPE_DEVICE;
 		break;
 	case 1:
 		regptr = &its->baser_coll_table;
-		entry_size = 8;
+		entry_size = abi->cte_esz;
 		device_type = GITS_BASER_TYPE_COLLECTION;
 		clearbits = GITS_BASER_INDIRECT;
 		break;
@@ -1425,7 +1476,6 @@ static int vgic_register_its_iodev(struct kvm *kvm, struct vgic_its *its)
 	(GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb)		| \
 	 GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner)		| \
 	 GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)		| \
-	 ((8ULL - 1) << GITS_BASER_ENTRY_SIZE_SHIFT)			| \
 	 GITS_BASER_PAGE_SIZE_64K)
 
 #define INITIAL_PROPBASER_VALUE						  \
@@ -1465,7 +1515,7 @@ static int vgic_its_create(struct kvm_device *dev, u32 type)
 
 	dev->private = its;
 
-	return 0;
+	return vgic_its_set_abi(its, NR_ITS_ABIS - 1);
 }
 
 static void vgic_its_destroy(struct kvm_device *kvm_dev)
@@ -1592,6 +1642,41 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
+/**
+ * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
+ * according to v0 ABI
+ */
+static int vgic_its_save_tables_v0(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_tables_v0 - Restore the ITS tables from guest RAM
+ * to internal data structs according to V0 ABI
+ *
+ */
+static int vgic_its_restore_tables_v0(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+static int vgic_its_commit_v0(struct vgic_its *its)
+{
+	const struct vgic_its_abi *abi;
+
+	abi = vgic_its_get_abi(its);
+	its->baser_coll_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
+	its->baser_device_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
+
+	its->baser_coll_table |= (GIC_ENCODE_SZ(abi->cte_esz, 5)
+					<< GITS_BASER_ENTRY_SIZE_SHIFT);
+
+	its->baser_device_table |= (GIC_ENCODE_SZ(abi->dte_esz, 5)
+					<< GITS_BASER_ENTRY_SIZE_SHIFT);
+	return 0;
+}
+
 static int vgic_its_has_attr(struct kvm_device *dev,
 			     struct kvm_device_attr *attr)
 {
-- 
2.5.5

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

* [PATCH v7 09/24] KVM: arm64: vgic-its: Introduce migration ABI infrastructure
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

We plan to support different migration ABIs, ie. characterizing
the ITS table layout format in guest RAM. For example, a new ABI
will be needed if vLPIs get supported for nested use case.

So let's introduce an array of supported ABIs (at the moment a single
ABI is supported though). The following characteristics are foreseen
to vary with the ABI: size of table entries, save/restore operation,
the way abi settings are applied.

By default the MAX_ABI_REV is applied on its creation. In subsequent
patches we will introduce a way for the userspace to change the ABI
in use.

The entry sizes now are set according to the ABI version and not
hardcoded anymore.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- define and use NR_ITS_ABIS
- reword kernel doc comment of @commit

v5 -> v6:
- rename abi into its_table_abi_versions
- kernel doc comments for struct vgic_its_abi
- comment GIC_ENCODE_SZ
- slighly rephrase the commit message

v5: creation and squash KVM: arm64: ITS: Report the ITE size in
    GITS_TYPER
---
 include/kvm/arm_vgic.h             |  3 ++
 include/linux/irqchip/arm-gic-v3.h |  5 ++
 virt/kvm/arm/vgic/vgic-its.c       | 93 ++++++++++++++++++++++++++++++++++++--
 3 files changed, 97 insertions(+), 4 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index c0b3d99..285474a 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -162,6 +162,9 @@ struct vgic_its {
 	u32			creadr;
 	u32			cwriter;
 
+	/* migration ABI revision in use */
+	u32			abi_rev;
+
 	/* Protects the device and collection lists */
 	struct mutex		its_lock;
 	struct list_head	device_list;
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 97cbca1..81ebe43 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -132,6 +132,9 @@
 #define GIC_BASER_SHAREABILITY(reg, type)				\
 	(GIC_BASER_##type << reg##_SHAREABILITY_SHIFT)
 
+/* encode a size field of width @w containing @n - 1 units */
+#define GIC_ENCODE_SZ(n, w) (((unsigned long)(n) - 1) & GENMASK_ULL(((w) - 1), 0))
+
 #define GICR_PROPBASER_SHAREABILITY_SHIFT		(10)
 #define GICR_PROPBASER_INNER_CACHEABILITY_SHIFT		(7)
 #define GICR_PROPBASER_OUTER_CACHEABILITY_SHIFT		(56)
@@ -232,6 +235,7 @@
 #define GITS_CTLR_QUIESCENT		(1U << 31)
 
 #define GITS_TYPER_PLPIS		(1UL << 0)
+#define GITS_TYPER_ITT_ENTRY_SIZE_SHIFT	4
 #define GITS_TYPER_IDBITS_SHIFT		8
 #define GITS_TYPER_DEVBITS_SHIFT	13
 #define GITS_TYPER_DEVBITS(r)		((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1)
@@ -290,6 +294,7 @@
 #define GITS_BASER_TYPE(r)		(((r) >> GITS_BASER_TYPE_SHIFT) & 7)
 #define GITS_BASER_ENTRY_SIZE_SHIFT		(48)
 #define GITS_BASER_ENTRY_SIZE(r)	((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0x1f) + 1)
+#define GITS_BASER_ENTRY_SIZE_MASK	GENMASK_ULL(52, 48)
 #define GITS_BASER_SHAREABILITY_SHIFT	(10)
 #define GITS_BASER_InnerShareable					\
 	GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index bf3ff09..4f6ea46 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -33,6 +33,10 @@
 #include "vgic.h"
 #include "vgic-mmio.h"
 
+static int vgic_its_save_tables_v0(struct vgic_its *its);
+static int vgic_its_restore_tables_v0(struct vgic_its *its);
+static int vgic_its_commit_v0(struct vgic_its *its);
+
 /*
  * Creates a new (reference to a) struct vgic_irq for a given LPI.
  * If this LPI is already mapped on another ITS, we increase its refcount
@@ -123,6 +127,50 @@ struct its_ite {
 	u32 event_id;
 };
 
+/**
+ * struct vgic_its_abi - ITS abi ops and settings
+ * @cte_esz: collection table entry size
+ * @dte_esz: device table entry size
+ * @ite_esz: interrupt translation table entry size
+ * @save tables: save the ITS tables into guest RAM
+ * @restore_tables: restore the ITS internal structs from tables
+ *  stored in guest RAM
+ * @commit: initialize the registers which expose the ABI settings,
+ *  especially the entry sizes
+ */
+struct vgic_its_abi {
+	int cte_esz;
+	int dte_esz;
+	int ite_esz;
+	int (*save_tables)(struct vgic_its *its);
+	int (*restore_tables)(struct vgic_its *its);
+	int (*commit)(struct vgic_its *its);
+};
+
+static const struct vgic_its_abi its_table_abi_versions[] = {
+	[0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
+	 .save_tables = vgic_its_save_tables_v0,
+	 .restore_tables = vgic_its_restore_tables_v0,
+	 .commit = vgic_its_commit_v0,
+	},
+};
+
+#define NR_ITS_ABIS	ARRAY_SIZE(its_table_abi_versions)
+
+inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
+{
+	return &its_table_abi_versions[its->abi_rev];
+}
+
+int vgic_its_set_abi(struct vgic_its *its, int rev)
+{
+	const struct vgic_its_abi *abi;
+
+	its->abi_rev = rev;
+	abi = vgic_its_get_abi(its);
+	return abi->commit(its);
+}
+
 /*
  * Find and returns a device in the device table for an ITS.
  * Must be called with the its_lock mutex held.
@@ -364,6 +412,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 					      struct vgic_its *its,
 					      gpa_t addr, unsigned int len)
 {
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
 	u64 reg = GITS_TYPER_PLPIS;
 
 	/*
@@ -376,6 +425,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 	 */
 	reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
 	reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
+	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
 
 	return extract_bytes(reg, addr & 7, len);
 }
@@ -1268,6 +1318,7 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 				      gpa_t addr, unsigned int len,
 				      unsigned long val)
 {
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
 	u64 entry_size, device_type;
 	u64 reg, *regptr, clearbits = 0;
 
@@ -1278,12 +1329,12 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
 	switch (BASER_INDEX(addr)) {
 	case 0:
 		regptr = &its->baser_device_table;
-		entry_size = 8;
+		entry_size = abi->dte_esz;
 		device_type = GITS_BASER_TYPE_DEVICE;
 		break;
 	case 1:
 		regptr = &its->baser_coll_table;
-		entry_size = 8;
+		entry_size = abi->cte_esz;
 		device_type = GITS_BASER_TYPE_COLLECTION;
 		clearbits = GITS_BASER_INDIRECT;
 		break;
@@ -1425,7 +1476,6 @@ static int vgic_register_its_iodev(struct kvm *kvm, struct vgic_its *its)
 	(GIC_BASER_CACHEABILITY(GITS_BASER, INNER, RaWb)		| \
 	 GIC_BASER_CACHEABILITY(GITS_BASER, OUTER, SameAsInner)		| \
 	 GIC_BASER_SHAREABILITY(GITS_BASER, InnerShareable)		| \
-	 ((8ULL - 1) << GITS_BASER_ENTRY_SIZE_SHIFT)			| \
 	 GITS_BASER_PAGE_SIZE_64K)
 
 #define INITIAL_PROPBASER_VALUE						  \
@@ -1465,7 +1515,7 @@ static int vgic_its_create(struct kvm_device *dev, u32 type)
 
 	dev->private = its;
 
-	return 0;
+	return vgic_its_set_abi(its, NR_ITS_ABIS - 1);
 }
 
 static void vgic_its_destroy(struct kvm_device *kvm_dev)
@@ -1592,6 +1642,41 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
+/**
+ * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
+ * according to v0 ABI
+ */
+static int vgic_its_save_tables_v0(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_tables_v0 - Restore the ITS tables from guest RAM
+ * to internal data structs according to V0 ABI
+ *
+ */
+static int vgic_its_restore_tables_v0(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+static int vgic_its_commit_v0(struct vgic_its *its)
+{
+	const struct vgic_its_abi *abi;
+
+	abi = vgic_its_get_abi(its);
+	its->baser_coll_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
+	its->baser_device_table &= ~GITS_BASER_ENTRY_SIZE_MASK;
+
+	its->baser_coll_table |= (GIC_ENCODE_SZ(abi->cte_esz, 5)
+					<< GITS_BASER_ENTRY_SIZE_SHIFT);
+
+	its->baser_device_table |= (GIC_ENCODE_SZ(abi->dte_esz, 5)
+					<< GITS_BASER_ENTRY_SIZE_SHIFT);
+	return 0;
+}
+
 static int vgic_its_has_attr(struct kvm_device *dev,
 			     struct kvm_device_attr *attr)
 {
-- 
2.5.5

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

* [PATCH v7 10/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_iidr
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

The GITS_IIDR revision field is used to encode the migration ABI
revision. So we need to restore it to check the table layout is
readable by the destination.

By writing the IIDR, userspace thus forces the ABI revision to be
used and this must be less than or equal to the max revision KVM
supports.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- use NR_ITS_ABIS
- introduce & use GITS_IIDR_REV_MASK

v5 -> v6:
- fix typos in the commit message
- dont't use update_64bit_reg anymore

v4 -> v5
- rename user_revision into abi_rev and REV into MAX_ABI_REV
- IIDR reports abi_rev set by userspace if any.
- If value set by userspace exceeds the max supported revision, an
  error is reported.
- add some defines

v4: creation
---
 include/linux/irqchip/arm-gic-v3.h |  5 +++++
 virt/kvm/arm/vgic/vgic-its.c       | 23 ++++++++++++++++++++---
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 81ebe43..2eaea30 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -242,6 +242,11 @@
 #define GITS_TYPER_PTA			(1UL << 19)
 #define GITS_TYPER_HWCOLLCNT_SHIFT	24
 
+#define GITS_IIDR_REV_SHIFT		12
+#define GITS_IIDR_REV_MASK		(0xf << GITS_IIDR_REV_SHIFT)
+#define GITS_IIDR_REV(r)		(((r) >> GITS_IIDR_REV_SHIFT) & 0xf)
+#define GITS_IIDR_PRODUCTID_SHIFT	24
+
 #define GITS_CBASER_VALID			(1ULL << 63)
 #define GITS_CBASER_SHAREABILITY_SHIFT		(10)
 #define GITS_CBASER_INNER_CACHEABILITY_SHIFT	(59)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 4f6ea46..9338efb 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -434,7 +434,23 @@ static unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm,
 					     struct vgic_its *its,
 					     gpa_t addr, unsigned int len)
 {
-	return (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+	u32 val;
+
+	val = (its->abi_rev << GITS_IIDR_REV_SHIFT) & GITS_IIDR_REV_MASK;
+	val |= (PRODUCT_ID_KVM << GITS_IIDR_PRODUCTID_SHIFT) | IMPLEMENTER_ARM;
+	return val;
+}
+
+static int vgic_mmio_uaccess_write_its_iidr(struct kvm *kvm,
+					    struct vgic_its *its,
+					    gpa_t addr, unsigned int len,
+					    unsigned long val)
+{
+	u32 rev = GITS_IIDR_REV(val);
+
+	if (rev >= NR_ITS_ABIS)
+		return -EINVAL;
+	return vgic_its_set_abi(its, rev);
 }
 
 static unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
@@ -1415,8 +1431,9 @@ static struct vgic_register_region its_registers[] = {
 	REGISTER_ITS_DESC(GITS_CTLR,
 		vgic_mmio_read_its_ctlr, vgic_mmio_write_its_ctlr, 4,
 		VGIC_ACCESS_32bit),
-	REGISTER_ITS_DESC(GITS_IIDR,
-		vgic_mmio_read_its_iidr, its_mmio_write_wi, 4,
+	REGISTER_ITS_DESC_UACCESS(GITS_IIDR,
+		vgic_mmio_read_its_iidr, its_mmio_write_wi,
+		vgic_mmio_uaccess_write_its_iidr, 4,
 		VGIC_ACCESS_32bit),
 	REGISTER_ITS_DESC(GITS_TYPER,
 		vgic_mmio_read_its_typer, its_mmio_write_wi, 8,
-- 
2.5.5

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

* [PATCH v7 10/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_iidr
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

The GITS_IIDR revision field is used to encode the migration ABI
revision. So we need to restore it to check the table layout is
readable by the destination.

By writing the IIDR, userspace thus forces the ABI revision to be
used and this must be less than or equal to the max revision KVM
supports.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- use NR_ITS_ABIS
- introduce & use GITS_IIDR_REV_MASK

v5 -> v6:
- fix typos in the commit message
- dont't use update_64bit_reg anymore

v4 -> v5
- rename user_revision into abi_rev and REV into MAX_ABI_REV
- IIDR reports abi_rev set by userspace if any.
- If value set by userspace exceeds the max supported revision, an
  error is reported.
- add some defines

v4: creation
---
 include/linux/irqchip/arm-gic-v3.h |  5 +++++
 virt/kvm/arm/vgic/vgic-its.c       | 23 ++++++++++++++++++++---
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 81ebe43..2eaea30 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -242,6 +242,11 @@
 #define GITS_TYPER_PTA			(1UL << 19)
 #define GITS_TYPER_HWCOLLCNT_SHIFT	24
 
+#define GITS_IIDR_REV_SHIFT		12
+#define GITS_IIDR_REV_MASK		(0xf << GITS_IIDR_REV_SHIFT)
+#define GITS_IIDR_REV(r)		(((r) >> GITS_IIDR_REV_SHIFT) & 0xf)
+#define GITS_IIDR_PRODUCTID_SHIFT	24
+
 #define GITS_CBASER_VALID			(1ULL << 63)
 #define GITS_CBASER_SHAREABILITY_SHIFT		(10)
 #define GITS_CBASER_INNER_CACHEABILITY_SHIFT	(59)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 4f6ea46..9338efb 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -434,7 +434,23 @@ static unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm,
 					     struct vgic_its *its,
 					     gpa_t addr, unsigned int len)
 {
-	return (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
+	u32 val;
+
+	val = (its->abi_rev << GITS_IIDR_REV_SHIFT) & GITS_IIDR_REV_MASK;
+	val |= (PRODUCT_ID_KVM << GITS_IIDR_PRODUCTID_SHIFT) | IMPLEMENTER_ARM;
+	return val;
+}
+
+static int vgic_mmio_uaccess_write_its_iidr(struct kvm *kvm,
+					    struct vgic_its *its,
+					    gpa_t addr, unsigned int len,
+					    unsigned long val)
+{
+	u32 rev = GITS_IIDR_REV(val);
+
+	if (rev >= NR_ITS_ABIS)
+		return -EINVAL;
+	return vgic_its_set_abi(its, rev);
 }
 
 static unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
@@ -1415,8 +1431,9 @@ static struct vgic_register_region its_registers[] = {
 	REGISTER_ITS_DESC(GITS_CTLR,
 		vgic_mmio_read_its_ctlr, vgic_mmio_write_its_ctlr, 4,
 		VGIC_ACCESS_32bit),
-	REGISTER_ITS_DESC(GITS_IIDR,
-		vgic_mmio_read_its_iidr, its_mmio_write_wi, 4,
+	REGISTER_ITS_DESC_UACCESS(GITS_IIDR,
+		vgic_mmio_read_its_iidr, its_mmio_write_wi,
+		vgic_mmio_uaccess_write_its_iidr, 4,
 		VGIC_ACCESS_32bit),
 	REGISTER_ITS_DESC(GITS_TYPER,
 		vgic_mmio_read_its_typer, its_mmio_write_wi, 8,
-- 
2.5.5

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

* [PATCH v7 11/24] KVM: arm64: vgic-its: Interpret MAPD Size field and check related errors
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

Up to now the MAPD's ITT size field has been ignored. It encodes
the number of eventid bit minus 1. It should be used to check
the eventid when a MAPTI command is issued on a device. Let's
store the number of eventid bits in the its_device and do the
check on MAPTI. Also make sure the ITT size field does
not exceed the GITS_TYPER IDBITS field.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

---
v6 -> v7:
- added Marc's R-b

v5 -> v6:
- add Christoffer's R-b
- rename nb_eventid_bits into num_eventid_bits

v4 -> v5:
- its_cmd_get_size macro now returns the actual number of eventid bits
- use GIC_ENCODE_SZ macro to encode ID_bits

v3 -> v4:
- VITS_TYPER_IDBITS set to 16 to be homogeneous with VITS_ESZ definition
  and correct users
- nb_eventid_bits correspond to the actual number of eventid bits
---
 include/linux/irqchip/arm-gic-v3.h |  2 ++
 virt/kvm/arm/vgic/vgic-its.c       | 15 ++++++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 2eaea30..be8bad0 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -347,9 +347,11 @@
 #define E_ITS_INT_UNMAPPED_INTERRUPT		0x010307
 #define E_ITS_CLEAR_UNMAPPED_INTERRUPT		0x010507
 #define E_ITS_MAPD_DEVICE_OOR			0x010801
+#define E_ITS_MAPD_ITTSIZE_OOR			0x010802
 #define E_ITS_MAPC_PROCNUM_OOR			0x010902
 #define E_ITS_MAPC_COLLECTION_OOR		0x010903
 #define E_ITS_MAPTI_UNMAPPED_DEVICE		0x010a04
+#define E_ITS_MAPTI_ID_OOR			0x010a05
 #define E_ITS_MAPTI_PHYSICALID_OOR		0x010a06
 #define E_ITS_INV_UNMAPPED_INTERRUPT		0x010c07
 #define E_ITS_INVALL_UNMAPPED_COLLECTION	0x010d09
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 9338efb..031f6ab 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -103,6 +103,7 @@ struct its_device {
 
 	/* the head for the list of ITTEs */
 	struct list_head itt_head;
+	u32 num_eventid_bits;
 	u32 device_id;
 };
 
@@ -224,6 +225,8 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 
 #define GIC_LPI_OFFSET 8192
 
+#define VITS_TYPER_IDBITS 16
+
 /*
  * Finds and returns a collection in the ITS collection table.
  * Must be called with the its_lock mutex held.
@@ -424,7 +427,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 	 * DevBits low - as least for the time being.
 	 */
 	reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
-	reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
+	reg |= GIC_ENCODE_SZ(VITS_TYPER_IDBITS, 5) << GITS_TYPER_IDBITS_SHIFT;
 	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
 
 	return extract_bytes(reg, addr & 7, len);
@@ -595,6 +598,7 @@ static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
 
 #define its_cmd_get_command(cmd)	its_cmd_mask_field(cmd, 0,  0,  8)
 #define its_cmd_get_deviceid(cmd)	its_cmd_mask_field(cmd, 0, 32, 32)
+#define its_cmd_get_size(cmd)		(its_cmd_mask_field(cmd, 1,  0,  5) + 1)
 #define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
 #define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
 #define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
@@ -785,6 +789,9 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	if (!device)
 		return E_ITS_MAPTI_UNMAPPED_DEVICE;
 
+	if (event_id >= BIT_ULL(device->num_eventid_bits))
+		return E_ITS_MAPTI_ID_OOR;
+
 	if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
 		lpi_nr = its_cmd_get_physical_id(its_cmd);
 	else
@@ -865,11 +872,15 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	bool valid = its_cmd_get_validbit(its_cmd);
+	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
 	struct its_device *device;
 
 	if (!vgic_its_check_id(its, its->baser_device_table, device_id))
 		return E_ITS_MAPD_DEVICE_OOR;
 
+	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
+		return E_ITS_MAPD_ITTSIZE_OOR;
+
 	device = find_its_device(its, device_id);
 
 	/*
@@ -892,6 +903,8 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 		return -ENOMEM;
 
 	device->device_id = device_id;
+	device->num_eventid_bits = num_eventid_bits;
+
 	INIT_LIST_HEAD(&device->itt_head);
 
 	list_add_tail(&device->dev_list, &its->device_list);
-- 
2.5.5

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

* [PATCH v7 11/24] KVM: arm64: vgic-its: Interpret MAPD Size field and check related errors
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Up to now the MAPD's ITT size field has been ignored. It encodes
the number of eventid bit minus 1. It should be used to check
the eventid when a MAPTI command is issued on a device. Let's
store the number of eventid bits in the its_device and do the
check on MAPTI. Also make sure the ITT size field does
not exceed the GITS_TYPER IDBITS field.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

---
v6 -> v7:
- added Marc's R-b

v5 -> v6:
- add Christoffer's R-b
- rename nb_eventid_bits into num_eventid_bits

v4 -> v5:
- its_cmd_get_size macro now returns the actual number of eventid bits
- use GIC_ENCODE_SZ macro to encode ID_bits

v3 -> v4:
- VITS_TYPER_IDBITS set to 16 to be homogeneous with VITS_ESZ definition
  and correct users
- nb_eventid_bits correspond to the actual number of eventid bits
---
 include/linux/irqchip/arm-gic-v3.h |  2 ++
 virt/kvm/arm/vgic/vgic-its.c       | 15 ++++++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 2eaea30..be8bad0 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -347,9 +347,11 @@
 #define E_ITS_INT_UNMAPPED_INTERRUPT		0x010307
 #define E_ITS_CLEAR_UNMAPPED_INTERRUPT		0x010507
 #define E_ITS_MAPD_DEVICE_OOR			0x010801
+#define E_ITS_MAPD_ITTSIZE_OOR			0x010802
 #define E_ITS_MAPC_PROCNUM_OOR			0x010902
 #define E_ITS_MAPC_COLLECTION_OOR		0x010903
 #define E_ITS_MAPTI_UNMAPPED_DEVICE		0x010a04
+#define E_ITS_MAPTI_ID_OOR			0x010a05
 #define E_ITS_MAPTI_PHYSICALID_OOR		0x010a06
 #define E_ITS_INV_UNMAPPED_INTERRUPT		0x010c07
 #define E_ITS_INVALL_UNMAPPED_COLLECTION	0x010d09
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 9338efb..031f6ab 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -103,6 +103,7 @@ struct its_device {
 
 	/* the head for the list of ITTEs */
 	struct list_head itt_head;
+	u32 num_eventid_bits;
 	u32 device_id;
 };
 
@@ -224,6 +225,8 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 
 #define GIC_LPI_OFFSET 8192
 
+#define VITS_TYPER_IDBITS 16
+
 /*
  * Finds and returns a collection in the ITS collection table.
  * Must be called with the its_lock mutex held.
@@ -424,7 +427,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 	 * DevBits low - as least for the time being.
 	 */
 	reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
-	reg |= 0x0f << GITS_TYPER_IDBITS_SHIFT;
+	reg |= GIC_ENCODE_SZ(VITS_TYPER_IDBITS, 5) << GITS_TYPER_IDBITS_SHIFT;
 	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
 
 	return extract_bytes(reg, addr & 7, len);
@@ -595,6 +598,7 @@ static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
 
 #define its_cmd_get_command(cmd)	its_cmd_mask_field(cmd, 0,  0,  8)
 #define its_cmd_get_deviceid(cmd)	its_cmd_mask_field(cmd, 0, 32, 32)
+#define its_cmd_get_size(cmd)		(its_cmd_mask_field(cmd, 1,  0,  5) + 1)
 #define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
 #define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
 #define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
@@ -785,6 +789,9 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	if (!device)
 		return E_ITS_MAPTI_UNMAPPED_DEVICE;
 
+	if (event_id >= BIT_ULL(device->num_eventid_bits))
+		return E_ITS_MAPTI_ID_OOR;
+
 	if (its_cmd_get_command(its_cmd) == GITS_CMD_MAPTI)
 		lpi_nr = its_cmd_get_physical_id(its_cmd);
 	else
@@ -865,11 +872,15 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 {
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	bool valid = its_cmd_get_validbit(its_cmd);
+	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
 	struct its_device *device;
 
 	if (!vgic_its_check_id(its, its->baser_device_table, device_id))
 		return E_ITS_MAPD_DEVICE_OOR;
 
+	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
+		return E_ITS_MAPD_ITTSIZE_OOR;
+
 	device = find_its_device(its, device_id);
 
 	/*
@@ -892,6 +903,8 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 		return -ENOMEM;
 
 	device->device_id = device_id;
+	device->num_eventid_bits = num_eventid_bits;
+
 	INIT_LIST_HEAD(&device->itt_head);
 
 	list_add_tail(&device->dev_list, &its->device_list);
-- 
2.5.5

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

* [PATCH v7 12/24] KVM: arm64: vgic-its: Interpret MAPD ITT_addr field
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

Up to now the MAPD ITT_addr had been ignored. We will need it
for save/restore. Let's record it in the its_device struct.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

---
v6 -> v7:
- added Christoffer's and Marc's R-b

v5 -> v6:
- fix its_cmd_get_ittaddr and pass 44 to its_cmd_mask_field

v4 -> v5:
- its_cmd_get_ittaddr macro now returns the actual ITT GPA

v3 -> v4:
- in vgic_its_cmd_handle_mapd, itt_addr directly is shifted
- correct ittaddr bitmask to support 48bit GPA
---
 virt/kvm/arm/vgic/vgic-its.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 031f6ab..7b95b73 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -104,6 +104,7 @@ struct its_device {
 	/* the head for the list of ITTEs */
 	struct list_head itt_head;
 	u32 num_eventid_bits;
+	gpa_t itt_addr;
 	u32 device_id;
 };
 
@@ -602,6 +603,7 @@ static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
 #define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
 #define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
 #define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
+#define its_cmd_get_ittaddr(cmd)	(its_cmd_mask_field(cmd, 2,  8, 44) << 8)
 #define its_cmd_get_target_addr(cmd)	its_cmd_mask_field(cmd, 2, 16, 32)
 #define its_cmd_get_validbit(cmd)	its_cmd_mask_field(cmd, 2, 63,  1)
 
@@ -873,6 +875,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	bool valid = its_cmd_get_validbit(its_cmd);
 	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
+	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
 	struct its_device *device;
 
 	if (!vgic_its_check_id(its, its->baser_device_table, device_id))
@@ -904,6 +907,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 
 	device->device_id = device_id;
 	device->num_eventid_bits = num_eventid_bits;
+	device->itt_addr = itt_addr;
 
 	INIT_LIST_HEAD(&device->itt_head);
 
-- 
2.5.5

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

* [PATCH v7 12/24] KVM: arm64: vgic-its: Interpret MAPD ITT_addr field
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Up to now the MAPD ITT_addr had been ignored. We will need it
for save/restore. Let's record it in the its_device struct.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

---
v6 -> v7:
- added Christoffer's and Marc's R-b

v5 -> v6:
- fix its_cmd_get_ittaddr and pass 44 to its_cmd_mask_field

v4 -> v5:
- its_cmd_get_ittaddr macro now returns the actual ITT GPA

v3 -> v4:
- in vgic_its_cmd_handle_mapd, itt_addr directly is shifted
- correct ittaddr bitmask to support 48bit GPA
---
 virt/kvm/arm/vgic/vgic-its.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 031f6ab..7b95b73 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -104,6 +104,7 @@ struct its_device {
 	/* the head for the list of ITTEs */
 	struct list_head itt_head;
 	u32 num_eventid_bits;
+	gpa_t itt_addr;
 	u32 device_id;
 };
 
@@ -602,6 +603,7 @@ static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size)
 #define its_cmd_get_id(cmd)		its_cmd_mask_field(cmd, 1,  0, 32)
 #define its_cmd_get_physical_id(cmd)	its_cmd_mask_field(cmd, 1, 32, 32)
 #define its_cmd_get_collection(cmd)	its_cmd_mask_field(cmd, 2,  0, 16)
+#define its_cmd_get_ittaddr(cmd)	(its_cmd_mask_field(cmd, 2,  8, 44) << 8)
 #define its_cmd_get_target_addr(cmd)	its_cmd_mask_field(cmd, 2, 16, 32)
 #define its_cmd_get_validbit(cmd)	its_cmd_mask_field(cmd, 2, 63,  1)
 
@@ -873,6 +875,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	u32 device_id = its_cmd_get_deviceid(its_cmd);
 	bool valid = its_cmd_get_validbit(its_cmd);
 	u8 num_eventid_bits = its_cmd_get_size(its_cmd);
+	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
 	struct its_device *device;
 
 	if (!vgic_its_check_id(its, its->baser_device_table, device_id))
@@ -904,6 +907,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 
 	device->device_id = device_id;
 	device->num_eventid_bits = num_eventid_bits;
+	device->itt_addr = itt_addr;
 
 	INIT_LIST_HEAD(&device->itt_head);
 
-- 
2.5.5

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

* [PATCH v7 13/24] KVM: arm64: vgic-its: Check the device id matches TYPER DEVBITS range
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

On MAPD we currently check the device id can be stored in the device table.
Let's first check it can be encoded within the range defined by TYPER
DEVBITS.

Also check the collection ID belongs to the 16 bit range as GITS_TYPER
CIL field equals to 0.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- s/CID/CIL
- added Christoffer's R-b

v4 -> v5:
- use GIC_ENCODE_SZ macro

v3 -> v4:
- VITS_TYPER_DEVBITS set to 16 for homogeneity
- use BIT_ULL
---
 virt/kvm/arm/vgic/vgic-its.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 7b95b73..bd1362e 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -227,6 +227,7 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 #define GIC_LPI_OFFSET 8192
 
 #define VITS_TYPER_IDBITS 16
+#define VITS_TYPER_DEVBITS 16
 
 /*
  * Finds and returns a collection in the ITS collection table.
@@ -427,7 +428,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 	 * To avoid memory waste in the guest, we keep the number of IDBits and
 	 * DevBits low - as least for the time being.
 	 */
-	reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
+	reg |= GIC_ENCODE_SZ(VITS_TYPER_DEVBITS, 5) << GITS_TYPER_DEVBITS_SHIFT;
 	reg |= GIC_ENCODE_SZ(VITS_TYPER_IDBITS, 5) << GITS_TYPER_IDBITS_SHIFT;
 	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
 
@@ -672,16 +673,30 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
  * Check whether an ID can be stored into the corresponding guest table.
  * For a direct table this is pretty easy, but gets a bit nasty for
  * indirect tables. We check whether the resulting guest physical address
- * is actually valid (covered by a memslot and guest accessbible).
+ * is actually valid (covered by a memslot and guest accessible).
  * For this we have to read the respective first level entry.
  */
-static bool vgic_its_check_id(struct vgic_its *its, u64 baser, int id)
+static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
 {
 	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
+	u64 indirect_ptr, type = GITS_BASER_TYPE(baser);
+	int esz = GITS_BASER_ENTRY_SIZE(baser);
 	int index;
-	u64 indirect_ptr;
 	gfn_t gfn;
-	int esz = GITS_BASER_ENTRY_SIZE(baser);
+
+	switch (type) {
+	case GITS_BASER_TYPE_DEVICE:
+		if (id >= BIT_ULL(VITS_TYPER_DEVBITS))
+			return false;
+		break;
+	case GITS_BASER_TYPE_COLLECTION:
+		/* as GITS_TYPER.CIL == 0, ITS supports 16-bit collection ID */
+		if (id >= BIT_ULL(16))
+			return false;
+		break;
+	default:
+		return false;
+	}
 
 	if (!(baser & GITS_BASER_INDIRECT)) {
 		phys_addr_t addr;
-- 
2.5.5

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

* [PATCH v7 13/24] KVM: arm64: vgic-its: Check the device id matches TYPER DEVBITS range
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

On MAPD we currently check the device id can be stored in the device table.
Let's first check it can be encoded within the range defined by TYPER
DEVBITS.

Also check the collection ID belongs to the 16 bit range as GITS_TYPER
CIL field equals to 0.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- s/CID/CIL
- added Christoffer's R-b

v4 -> v5:
- use GIC_ENCODE_SZ macro

v3 -> v4:
- VITS_TYPER_DEVBITS set to 16 for homogeneity
- use BIT_ULL
---
 virt/kvm/arm/vgic/vgic-its.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 7b95b73..bd1362e 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -227,6 +227,7 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 #define GIC_LPI_OFFSET 8192
 
 #define VITS_TYPER_IDBITS 16
+#define VITS_TYPER_DEVBITS 16
 
 /*
  * Finds and returns a collection in the ITS collection table.
@@ -427,7 +428,7 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
 	 * To avoid memory waste in the guest, we keep the number of IDBits and
 	 * DevBits low - as least for the time being.
 	 */
-	reg |= 0x0f << GITS_TYPER_DEVBITS_SHIFT;
+	reg |= GIC_ENCODE_SZ(VITS_TYPER_DEVBITS, 5) << GITS_TYPER_DEVBITS_SHIFT;
 	reg |= GIC_ENCODE_SZ(VITS_TYPER_IDBITS, 5) << GITS_TYPER_IDBITS_SHIFT;
 	reg |= GIC_ENCODE_SZ(abi->ite_esz, 4) << GITS_TYPER_ITT_ENTRY_SIZE_SHIFT;
 
@@ -672,16 +673,30 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
  * Check whether an ID can be stored into the corresponding guest table.
  * For a direct table this is pretty easy, but gets a bit nasty for
  * indirect tables. We check whether the resulting guest physical address
- * is actually valid (covered by a memslot and guest accessbible).
+ * is actually valid (covered by a memslot and guest accessible).
  * For this we have to read the respective first level entry.
  */
-static bool vgic_its_check_id(struct vgic_its *its, u64 baser, int id)
+static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
 {
 	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
+	u64 indirect_ptr, type = GITS_BASER_TYPE(baser);
+	int esz = GITS_BASER_ENTRY_SIZE(baser);
 	int index;
-	u64 indirect_ptr;
 	gfn_t gfn;
-	int esz = GITS_BASER_ENTRY_SIZE(baser);
+
+	switch (type) {
+	case GITS_BASER_TYPE_DEVICE:
+		if (id >= BIT_ULL(VITS_TYPER_DEVBITS))
+			return false;
+		break;
+	case GITS_BASER_TYPE_COLLECTION:
+		/* as GITS_TYPER.CIL == 0, ITS supports 16-bit collection ID */
+		if (id >= BIT_ULL(16))
+			return false;
+		break;
+	default:
+		return false;
+	}
 
 	if (!(baser & GITS_BASER_INDIRECT)) {
 		phys_addr_t addr;
-- 
2.5.5

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

* [PATCH v7 14/24] KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

this new helper synchronizes the irq pending_latch
with the LPI pending bit status found in rdist pending table.
As the status is consumed, we reset the bit in pending table.

As we need the PENDBASER_ADDRESS() in vgic-v3, let's move its
definition in the irqchip header. We restore the full length
of the field, ie [51:16]. Same for PROPBASER_ADDRESS with full
field length of [51:12].

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---

v6: new
---
 include/linux/irqchip/arm-gic-v3.h |  2 ++
 virt/kvm/arm/vgic/vgic-its.c       |  6 ++----
 virt/kvm/arm/vgic/vgic-v3.c        | 44 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h           |  1 +
 4 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index be8bad0..fffb912 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -159,6 +159,8 @@
 #define GICR_PROPBASER_RaWaWb	GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWb)
 
 #define GICR_PROPBASER_IDBITS_MASK			(0x1f)
+#define GICR_PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 12))
+#define GICR_PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 16))
 
 #define GICR_PENDBASER_SHAREABILITY_SHIFT		(10)
 #define GICR_PENDBASER_INNER_CACHEABILITY_SHIFT		(7)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index bd1362e..3601790 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -221,8 +221,6 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
  */
 #define BASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
 #define CBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
-#define PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
-#define PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
 
 #define GIC_LPI_OFFSET 8192
 
@@ -257,7 +255,7 @@ static struct its_collection *find_collection(struct vgic_its *its, int coll_id)
 static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
 			     struct kvm_vcpu *filter_vcpu)
 {
-	u64 propbase = PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
+	u64 propbase = GICR_PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
 	u8 prop;
 	int ret;
 
@@ -369,7 +367,7 @@ static u32 max_lpis_propbaser(u64 propbaser)
  */
 static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
 {
-	gpa_t pendbase = PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
+	gpa_t pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
 	struct vgic_irq *irq;
 	int last_byte_offset = -1;
 	int ret = 0;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index be0f4c3..0d753ae 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -252,6 +252,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
+int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
+{
+	struct kvm_vcpu *vcpu;
+	int byte_offset, bit_nr;
+	gpa_t pendbase, ptr;
+	bool status;
+	u8 val;
+	int ret;
+
+retry:
+	vcpu = irq->target_vcpu;
+	if (!vcpu)
+		return 0;
+
+	pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
+
+	byte_offset = irq->intid / BITS_PER_BYTE;
+	bit_nr = irq->intid % BITS_PER_BYTE;
+	ptr = pendbase + byte_offset;
+
+	ret = kvm_read_guest(kvm, ptr, &val, 1);
+	if (ret)
+		return ret;
+
+	status = val & (1 << bit_nr);
+
+	spin_lock(&irq->irq_lock);
+	if (irq->target_vcpu != vcpu) {
+		spin_unlock(&irq->irq_lock);
+		goto retry;
+	}
+	irq->pending_latch = status;
+	vgic_queue_irq_unlock(vcpu->kvm, irq);
+
+	if (status) {
+		/* clear consumed data */
+		val &= ~(1 << bit_nr);
+		ret = kvm_write_guest(kvm, ptr, &val, 1);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 /* check for overlapping regions and for regions crossing the end of memory */
 static bool vgic_v3_check_base(struct kvm *kvm)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index b87f1c6..309ab64 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -157,6 +157,7 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
+int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 
 int vgic_register_its_iodevs(struct kvm *kvm);
-- 
2.5.5

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

* [PATCH v7 14/24] KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

this new helper synchronizes the irq pending_latch
with the LPI pending bit status found in rdist pending table.
As the status is consumed, we reset the bit in pending table.

As we need the PENDBASER_ADDRESS() in vgic-v3, let's move its
definition in the irqchip header. We restore the full length
of the field, ie [51:16]. Same for PROPBASER_ADDRESS with full
field length of [51:12].

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---

v6: new
---
 include/linux/irqchip/arm-gic-v3.h |  2 ++
 virt/kvm/arm/vgic/vgic-its.c       |  6 ++----
 virt/kvm/arm/vgic/vgic-v3.c        | 44 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h           |  1 +
 4 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index be8bad0..fffb912 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -159,6 +159,8 @@
 #define GICR_PROPBASER_RaWaWb	GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWb)
 
 #define GICR_PROPBASER_IDBITS_MASK			(0x1f)
+#define GICR_PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 12))
+#define GICR_PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 16))
 
 #define GICR_PENDBASER_SHAREABILITY_SHIFT		(10)
 #define GICR_PENDBASER_INNER_CACHEABILITY_SHIFT		(7)
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index bd1362e..3601790 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -221,8 +221,6 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
  */
 #define BASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
 #define CBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
-#define PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
-#define PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
 
 #define GIC_LPI_OFFSET 8192
 
@@ -257,7 +255,7 @@ static struct its_collection *find_collection(struct vgic_its *its, int coll_id)
 static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
 			     struct kvm_vcpu *filter_vcpu)
 {
-	u64 propbase = PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
+	u64 propbase = GICR_PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
 	u8 prop;
 	int ret;
 
@@ -369,7 +367,7 @@ static u32 max_lpis_propbaser(u64 propbaser)
  */
 static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
 {
-	gpa_t pendbase = PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
+	gpa_t pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
 	struct vgic_irq *irq;
 	int last_byte_offset = -1;
 	int ret = 0;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index be0f4c3..0d753ae 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -252,6 +252,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
 }
 
+int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
+{
+	struct kvm_vcpu *vcpu;
+	int byte_offset, bit_nr;
+	gpa_t pendbase, ptr;
+	bool status;
+	u8 val;
+	int ret;
+
+retry:
+	vcpu = irq->target_vcpu;
+	if (!vcpu)
+		return 0;
+
+	pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
+
+	byte_offset = irq->intid / BITS_PER_BYTE;
+	bit_nr = irq->intid % BITS_PER_BYTE;
+	ptr = pendbase + byte_offset;
+
+	ret = kvm_read_guest(kvm, ptr, &val, 1);
+	if (ret)
+		return ret;
+
+	status = val & (1 << bit_nr);
+
+	spin_lock(&irq->irq_lock);
+	if (irq->target_vcpu != vcpu) {
+		spin_unlock(&irq->irq_lock);
+		goto retry;
+	}
+	irq->pending_latch = status;
+	vgic_queue_irq_unlock(vcpu->kvm, irq);
+
+	if (status) {
+		/* clear consumed data */
+		val &= ~(1 << bit_nr);
+		ret = kvm_write_guest(kvm, ptr, &val, 1);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 /* check for overlapping regions and for regions crossing the end of memory */
 static bool vgic_v3_check_base(struct kvm *kvm)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index b87f1c6..309ab64 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -157,6 +157,7 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
+int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 
 int vgic_register_its_iodevs(struct kvm *kvm);
-- 
2.5.5

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

* [PATCH v7 15/24] KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

When creating the lpi we now ask the redistributor what is the state
of the LPI (priority, enabled, pending).

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- fix a typo

v6: creation
---
 virt/kvm/arm/vgic/vgic-its.c | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 3601790..ffd0a80 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -36,6 +36,8 @@
 static int vgic_its_save_tables_v0(struct vgic_its *its);
 static int vgic_its_restore_tables_v0(struct vgic_its *its);
 static int vgic_its_commit_v0(struct vgic_its *its);
+static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
+			     struct kvm_vcpu *filter_vcpu);
 
 /*
  * Creates a new (reference to a) struct vgic_irq for a given LPI.
@@ -44,10 +46,12 @@ static int vgic_its_commit_v0(struct vgic_its *its);
  * If this is a "new" LPI, we allocate and initialize a new struct vgic_irq.
  * This function returns a pointer to the _unlocked_ structure.
  */
-static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
+static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
+				     struct kvm_vcpu *vcpu)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq;
+	int ret;
 
 	/* In this case there is no put, since we keep the reference. */
 	if (irq)
@@ -64,6 +68,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
 	irq->config = VGIC_CONFIG_EDGE;
 	kref_init(&irq->refcount);
 	irq->intid = intid;
+	irq->target_vcpu = vcpu;
 
 	spin_lock(&dist->lpi_list_lock);
 
@@ -95,6 +100,19 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
 out_unlock:
 	spin_unlock(&dist->lpi_list_lock);
 
+	/*
+	 * We "cache" the configuration table entries in our struct vgic_irq's.
+	 * However we only have those structs for mapped IRQs, so we read in
+	 * the respective config data from memory here upon mapping the LPI.
+	 */
+	ret = update_lpi_config(kvm, irq, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = vgic_v3_lpi_sync_pending_status(kvm, irq);
+	if (ret)
+		return ERR_PTR(ret);
+
 	return irq;
 }
 
@@ -795,6 +813,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	u32 event_id = its_cmd_get_id(its_cmd);
 	u32 coll_id = its_cmd_get_collection(its_cmd);
 	struct its_ite *ite;
+	struct kvm_vcpu *vcpu = NULL;
 	struct its_device *device;
 	struct its_collection *collection, *new_coll = NULL;
 	int lpi_nr;
@@ -840,7 +859,10 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	ite->collection = collection;
 	ite->lpi = lpi_nr;
 
-	irq = vgic_add_lpi(kvm, lpi_nr);
+	if (its_is_collection_mapped(collection))
+		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
+
+	irq = vgic_add_lpi(kvm, lpi_nr, vcpu);
 	if (IS_ERR(irq)) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
@@ -849,15 +871,6 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	}
 	ite->irq = irq;
 
-	update_affinity_ite(kvm, ite);
-
-	/*
-	 * We "cache" the configuration table entries in out struct vgic_irq's.
-	 * However we only have those structs for mapped IRQs, so we read in
-	 * the respective config data from memory here upon mapping the LPI.
-	 */
-	update_lpi_config(kvm, ite->irq, NULL);
-
 	return 0;
 }
 
-- 
2.5.5

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

* [PATCH v7 15/24] KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

When creating the lpi we now ask the redistributor what is the state
of the LPI (priority, enabled, pending).

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- fix a typo

v6: creation
---
 virt/kvm/arm/vgic/vgic-its.c | 35 ++++++++++++++++++++++++-----------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 3601790..ffd0a80 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -36,6 +36,8 @@
 static int vgic_its_save_tables_v0(struct vgic_its *its);
 static int vgic_its_restore_tables_v0(struct vgic_its *its);
 static int vgic_its_commit_v0(struct vgic_its *its);
+static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
+			     struct kvm_vcpu *filter_vcpu);
 
 /*
  * Creates a new (reference to a) struct vgic_irq for a given LPI.
@@ -44,10 +46,12 @@ static int vgic_its_commit_v0(struct vgic_its *its);
  * If this is a "new" LPI, we allocate and initialize a new struct vgic_irq.
  * This function returns a pointer to the _unlocked_ structure.
  */
-static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
+static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
+				     struct kvm_vcpu *vcpu)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq;
+	int ret;
 
 	/* In this case there is no put, since we keep the reference. */
 	if (irq)
@@ -64,6 +68,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
 	irq->config = VGIC_CONFIG_EDGE;
 	kref_init(&irq->refcount);
 	irq->intid = intid;
+	irq->target_vcpu = vcpu;
 
 	spin_lock(&dist->lpi_list_lock);
 
@@ -95,6 +100,19 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid)
 out_unlock:
 	spin_unlock(&dist->lpi_list_lock);
 
+	/*
+	 * We "cache" the configuration table entries in our struct vgic_irq's.
+	 * However we only have those structs for mapped IRQs, so we read in
+	 * the respective config data from memory here upon mapping the LPI.
+	 */
+	ret = update_lpi_config(kvm, irq, NULL);
+	if (ret)
+		return ERR_PTR(ret);
+
+	ret = vgic_v3_lpi_sync_pending_status(kvm, irq);
+	if (ret)
+		return ERR_PTR(ret);
+
 	return irq;
 }
 
@@ -795,6 +813,7 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	u32 event_id = its_cmd_get_id(its_cmd);
 	u32 coll_id = its_cmd_get_collection(its_cmd);
 	struct its_ite *ite;
+	struct kvm_vcpu *vcpu = NULL;
 	struct its_device *device;
 	struct its_collection *collection, *new_coll = NULL;
 	int lpi_nr;
@@ -840,7 +859,10 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	ite->collection = collection;
 	ite->lpi = lpi_nr;
 
-	irq = vgic_add_lpi(kvm, lpi_nr);
+	if (its_is_collection_mapped(collection))
+		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
+
+	irq = vgic_add_lpi(kvm, lpi_nr, vcpu);
 	if (IS_ERR(irq)) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
@@ -849,15 +871,6 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	}
 	ite->irq = irq;
 
-	update_affinity_ite(kvm, ite);
-
-	/*
-	 * We "cache" the configuration table entries in out struct vgic_irq's.
-	 * However we only have those structs for mapped IRQs, so we read in
-	 * the respective config data from memory here upon mapping the LPI.
-	 */
-	update_lpi_config(kvm, ite->irq, NULL);
-
 	return 0;
 }
 
-- 
2.5.5

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

* [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
- KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
- KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
  structures.

We hold the vcpus lock during the save and restore to make
sure no vcpu is running.

At this stage the functionality is not yet implemented. Only
the skeleton is put in place.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- also hold the its_lock on save and restore

v5 -> v6:
- remove the pending table sync from the ITS table restore

v4 -> v5:
- use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
- rename *flush* into *save*
- call its_sync_lpi_pending_table at the end of restore
- use abi framework

v3 -> v4:
- pass kvm struct handle to vgic_its_flush/restore_pending_tables
- take the kvm lock and vcpu locks
- ABI revision check
- check attr->attr is null

v1 -> v2:
- remove useless kvm parameter
---
 arch/arm/include/uapi/asm/kvm.h   |   4 +-
 arch/arm64/include/uapi/asm/kvm.h |   4 +-
 virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
 3 files changed, 109 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 4beb83b..8e6563c 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -199,7 +199,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
 #define VGIC_LEVEL_INFO_LINE_LEVEL	0
 
-#define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
+#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
+#define   KVM_DEV_ARM_ITS_SAVE_TABLES		1
+#define   KVM_DEV_ARM_ITS_RESTORE_TABLES	2
 
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 7e8dd69..1e35115 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -219,7 +219,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
 #define VGIC_LEVEL_INFO_LINE_LEVEL	0
 
-#define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
+#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
+#define   KVM_DEV_ARM_ITS_SAVE_TABLES           1
+#define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
 
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index ffd0a80..cb7ae4c 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1703,12 +1703,71 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 }
 
 /**
+ * vgic_its_save_device_tables - Save the device table and all ITT
+ * into guest RAM
+ */
+static int vgic_its_save_device_tables(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_device_tables - Restore the device table and all ITT
+ * from guest RAM to internal data structs
+ */
+static int vgic_its_restore_device_tables(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_save_collection_table - Save the collection table into
+ * guest RAM
+ */
+static int vgic_its_save_collection_table(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_collection_table - reads the collection table
+ * in guest memory and restores the ITS internal state. Requires the
+ * BASER registers to be restored before.
+ */
+static int vgic_its_restore_collection_table(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
  * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
  * according to v0 ABI
  */
 static int vgic_its_save_tables_v0(struct vgic_its *its)
 {
-	return -ENXIO;
+	struct kvm *kvm = its->dev->kvm;
+	int ret;
+
+	mutex_lock(&kvm->lock);
+	mutex_lock(&its->its_lock);
+
+	if (!lock_all_vcpus(kvm)) {
+		mutex_unlock(&its->its_lock);
+		mutex_unlock(&kvm->lock);
+		return -EBUSY;
+	}
+
+	ret = vgic_its_save_device_tables(its);
+	if (ret)
+		goto out;
+
+	ret = vgic_its_save_collection_table(its);
+
+out:
+	unlock_all_vcpus(kvm);
+	mutex_unlock(&its->its_lock);
+	mutex_unlock(&kvm->lock);
+	return ret;
 }
 
 /**
@@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
  */
 static int vgic_its_restore_tables_v0(struct vgic_its *its)
 {
-	return -ENXIO;
+	struct kvm *kvm = its->dev->kvm;
+	int ret;
+
+	mutex_lock(&kvm->lock);
+	mutex_lock(&its->its_lock);
+
+	if (!lock_all_vcpus(kvm)) {
+		mutex_unlock(&its->its_lock);
+		mutex_unlock(&kvm->lock);
+		return -EBUSY;
+	}
+
+	ret = vgic_its_restore_collection_table(its);
+	if (ret)
+		goto out;
+
+	ret = vgic_its_restore_device_tables(its);
+
+out:
+	unlock_all_vcpus(kvm);
+	mutex_unlock(&its->its_lock);
+	mutex_unlock(&kvm->lock);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * On restore path, MSI injections can happen before the
+	 * first VCPU run so let's complete the GIC init here.
+	 */
+	return kvm_vgic_map_resources(its->dev->kvm);
 }
 
 static int vgic_its_commit_v0(struct vgic_its *its)
@@ -1751,6 +1840,10 @@ static int vgic_its_has_attr(struct kvm_device *dev,
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			return 0;
+		case KVM_DEV_ARM_ITS_SAVE_TABLES:
+			return 0;
+		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
+			return 0;
 		}
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
@@ -1786,14 +1879,20 @@ static int vgic_its_set_attr(struct kvm_device *dev,
 
 		return 0;
 	}
-	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			its->initialized = true;
 
 			return 0;
+		case KVM_DEV_ARM_ITS_SAVE_TABLES:
+			return abi->save_tables(its);
+		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
+			return abi->restore_tables(its);
 		}
-		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
 		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
 		u64 reg;
-- 
2.5.5

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

* [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
- KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
- KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
  structures.

We hold the vcpus lock during the save and restore to make
sure no vcpu is running.

At this stage the functionality is not yet implemented. Only
the skeleton is put in place.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v6 -> v7:
- also hold the its_lock on save and restore

v5 -> v6:
- remove the pending table sync from the ITS table restore

v4 -> v5:
- use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
- rename *flush* into *save*
- call its_sync_lpi_pending_table at the end of restore
- use abi framework

v3 -> v4:
- pass kvm struct handle to vgic_its_flush/restore_pending_tables
- take the kvm lock and vcpu locks
- ABI revision check
- check attr->attr is null

v1 -> v2:
- remove useless kvm parameter
---
 arch/arm/include/uapi/asm/kvm.h   |   4 +-
 arch/arm64/include/uapi/asm/kvm.h |   4 +-
 virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
 3 files changed, 109 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 4beb83b..8e6563c 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -199,7 +199,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
 #define VGIC_LEVEL_INFO_LINE_LEVEL	0
 
-#define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
+#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
+#define   KVM_DEV_ARM_ITS_SAVE_TABLES		1
+#define   KVM_DEV_ARM_ITS_RESTORE_TABLES	2
 
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 7e8dd69..1e35115 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -219,7 +219,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
 #define VGIC_LEVEL_INFO_LINE_LEVEL	0
 
-#define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
+#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
+#define   KVM_DEV_ARM_ITS_SAVE_TABLES           1
+#define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
 
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index ffd0a80..cb7ae4c 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1703,12 +1703,71 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 }
 
 /**
+ * vgic_its_save_device_tables - Save the device table and all ITT
+ * into guest RAM
+ */
+static int vgic_its_save_device_tables(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_device_tables - Restore the device table and all ITT
+ * from guest RAM to internal data structs
+ */
+static int vgic_its_restore_device_tables(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_save_collection_table - Save the collection table into
+ * guest RAM
+ */
+static int vgic_its_save_collection_table(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_restore_collection_table - reads the collection table
+ * in guest memory and restores the ITS internal state. Requires the
+ * BASER registers to be restored before.
+ */
+static int vgic_its_restore_collection_table(struct vgic_its *its)
+{
+	return -ENXIO;
+}
+
+/**
  * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
  * according to v0 ABI
  */
 static int vgic_its_save_tables_v0(struct vgic_its *its)
 {
-	return -ENXIO;
+	struct kvm *kvm = its->dev->kvm;
+	int ret;
+
+	mutex_lock(&kvm->lock);
+	mutex_lock(&its->its_lock);
+
+	if (!lock_all_vcpus(kvm)) {
+		mutex_unlock(&its->its_lock);
+		mutex_unlock(&kvm->lock);
+		return -EBUSY;
+	}
+
+	ret = vgic_its_save_device_tables(its);
+	if (ret)
+		goto out;
+
+	ret = vgic_its_save_collection_table(its);
+
+out:
+	unlock_all_vcpus(kvm);
+	mutex_unlock(&its->its_lock);
+	mutex_unlock(&kvm->lock);
+	return ret;
 }
 
 /**
@@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
  */
 static int vgic_its_restore_tables_v0(struct vgic_its *its)
 {
-	return -ENXIO;
+	struct kvm *kvm = its->dev->kvm;
+	int ret;
+
+	mutex_lock(&kvm->lock);
+	mutex_lock(&its->its_lock);
+
+	if (!lock_all_vcpus(kvm)) {
+		mutex_unlock(&its->its_lock);
+		mutex_unlock(&kvm->lock);
+		return -EBUSY;
+	}
+
+	ret = vgic_its_restore_collection_table(its);
+	if (ret)
+		goto out;
+
+	ret = vgic_its_restore_device_tables(its);
+
+out:
+	unlock_all_vcpus(kvm);
+	mutex_unlock(&its->its_lock);
+	mutex_unlock(&kvm->lock);
+
+	if (ret)
+		return ret;
+
+	/*
+	 * On restore path, MSI injections can happen before the
+	 * first VCPU run so let's complete the GIC init here.
+	 */
+	return kvm_vgic_map_resources(its->dev->kvm);
 }
 
 static int vgic_its_commit_v0(struct vgic_its *its)
@@ -1751,6 +1840,10 @@ static int vgic_its_has_attr(struct kvm_device *dev,
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			return 0;
+		case KVM_DEV_ARM_ITS_SAVE_TABLES:
+			return 0;
+		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
+			return 0;
 		}
 		break;
 	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
@@ -1786,14 +1879,20 @@ static int vgic_its_set_attr(struct kvm_device *dev,
 
 		return 0;
 	}
-	case KVM_DEV_ARM_VGIC_GRP_CTRL:
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			its->initialized = true;
 
 			return 0;
+		case KVM_DEV_ARM_ITS_SAVE_TABLES:
+			return abi->save_tables(its);
+		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
+			return abi->restore_tables(its);
 		}
-		break;
+	}
 	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
 		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
 		u64 reg;
-- 
2.5.5

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

* [PATCH v7 17/24] KVM: arm64: vgic-its: vgic_its_alloc_ite/device
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

Add two new helpers to allocate an its ite and an its device.
This will avoid duplication on restore path.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
added Christoffer's R-b

v5 -> v6:
- remove Marc's A-b
- both functions now return the newly allocated struct

v4 -> v5:
- add Marc's A-b

v3 -> v4:
- fix allocation
- add comment about its_lock mutex hold

v1 -> v2:
- report itt_size fix and remove ITE_SIZE
- s/itte/ite/g
---
 virt/kvm/arm/vgic/vgic-its.c | 68 ++++++++++++++++++++++++++++++--------------
 1 file changed, 47 insertions(+), 21 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index cb7ae4c..737ba3c 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -802,6 +802,25 @@ static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
 	kfree(collection);
 }
 
+/* Must be called with its_lock mutex held */
+static struct its_ite *vgic_its_alloc_ite(struct its_device *device,
+					  struct its_collection *collection,
+					  u32 lpi_id, u32 event_id)
+{
+	struct its_ite *ite;
+
+	ite = kzalloc(sizeof(*ite), GFP_KERNEL);
+	if (!ite)
+		return ERR_PTR(-ENOMEM);
+
+	ite->event_id	= event_id;
+	ite->collection = collection;
+	ite->lpi = lpi_id;
+
+	list_add_tail(&ite->ite_list, &device->itt_head);
+	return ite;
+}
+
 /*
  * The MAPTI and MAPI commands map LPIs to ITTEs.
  * Must be called with its_lock mutex held.
@@ -816,8 +835,8 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	struct kvm_vcpu *vcpu = NULL;
 	struct its_device *device;
 	struct its_collection *collection, *new_coll = NULL;
-	int lpi_nr;
 	struct vgic_irq *irq;
+	int lpi_nr;
 
 	device = find_its_device(its, device_id);
 	if (!device)
@@ -846,19 +865,13 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 		new_coll = collection;
 	}
 
-	ite = kzalloc(sizeof(struct its_ite), GFP_KERNEL);
-	if (!ite) {
+	ite = vgic_its_alloc_ite(device, collection, lpi_nr, event_id);
+	if (IS_ERR(ite)) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
-		return -ENOMEM;
+		return PTR_ERR(ite);
 	}
 
-	ite->event_id	= event_id;
-	list_add_tail(&ite->ite_list, &device->itt_head);
-
-	ite->collection = collection;
-	ite->lpi = lpi_nr;
-
 	if (its_is_collection_mapped(collection))
 		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
 
@@ -891,6 +904,26 @@ static void vgic_its_unmap_device(struct kvm *kvm, struct its_device *device)
 	kfree(device);
 }
 
+/* Must be called with its_lock mutex held */
+static struct its_device *vgic_its_alloc_device(struct vgic_its *its,
+						u32 device_id, gpa_t itt_addr,
+						u8 num_eventid_bits)
+{
+	struct its_device *device;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return ERR_PTR(-ENOMEM);
+
+	device->device_id = device_id;
+	device->itt_addr = itt_addr;
+	device->num_eventid_bits = num_eventid_bits;
+	INIT_LIST_HEAD(&device->itt_head);
+
+	list_add_tail(&device->dev_list, &its->device_list);
+	return device;
+}
+
 /*
  * MAPD maps or unmaps a device ID to Interrupt Translation Tables (ITTs).
  * Must be called with the its_lock mutex held.
@@ -927,17 +960,10 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	if (!valid)
 		return 0;
 
-	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
-	if (!device)
-		return -ENOMEM;
-
-	device->device_id = device_id;
-	device->num_eventid_bits = num_eventid_bits;
-	device->itt_addr = itt_addr;
-
-	INIT_LIST_HEAD(&device->itt_head);
-
-	list_add_tail(&device->dev_list, &its->device_list);
+	device = vgic_its_alloc_device(its, device_id, itt_addr,
+				       num_eventid_bits);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
 
 	return 0;
 }
-- 
2.5.5

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

* [PATCH v7 17/24] KVM: arm64: vgic-its: vgic_its_alloc_ite/device
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Add two new helpers to allocate an its ite and an its device.
This will avoid duplication on restore path.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
added Christoffer's R-b

v5 -> v6:
- remove Marc's A-b
- both functions now return the newly allocated struct

v4 -> v5:
- add Marc's A-b

v3 -> v4:
- fix allocation
- add comment about its_lock mutex hold

v1 -> v2:
- report itt_size fix and remove ITE_SIZE
- s/itte/ite/g
---
 virt/kvm/arm/vgic/vgic-its.c | 68 ++++++++++++++++++++++++++++++--------------
 1 file changed, 47 insertions(+), 21 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index cb7ae4c..737ba3c 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -802,6 +802,25 @@ static void vgic_its_free_collection(struct vgic_its *its, u32 coll_id)
 	kfree(collection);
 }
 
+/* Must be called with its_lock mutex held */
+static struct its_ite *vgic_its_alloc_ite(struct its_device *device,
+					  struct its_collection *collection,
+					  u32 lpi_id, u32 event_id)
+{
+	struct its_ite *ite;
+
+	ite = kzalloc(sizeof(*ite), GFP_KERNEL);
+	if (!ite)
+		return ERR_PTR(-ENOMEM);
+
+	ite->event_id	= event_id;
+	ite->collection = collection;
+	ite->lpi = lpi_id;
+
+	list_add_tail(&ite->ite_list, &device->itt_head);
+	return ite;
+}
+
 /*
  * The MAPTI and MAPI commands map LPIs to ITTEs.
  * Must be called with its_lock mutex held.
@@ -816,8 +835,8 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 	struct kvm_vcpu *vcpu = NULL;
 	struct its_device *device;
 	struct its_collection *collection, *new_coll = NULL;
-	int lpi_nr;
 	struct vgic_irq *irq;
+	int lpi_nr;
 
 	device = find_its_device(its, device_id);
 	if (!device)
@@ -846,19 +865,13 @@ static int vgic_its_cmd_handle_mapi(struct kvm *kvm, struct vgic_its *its,
 		new_coll = collection;
 	}
 
-	ite = kzalloc(sizeof(struct its_ite), GFP_KERNEL);
-	if (!ite) {
+	ite = vgic_its_alloc_ite(device, collection, lpi_nr, event_id);
+	if (IS_ERR(ite)) {
 		if (new_coll)
 			vgic_its_free_collection(its, coll_id);
-		return -ENOMEM;
+		return PTR_ERR(ite);
 	}
 
-	ite->event_id	= event_id;
-	list_add_tail(&ite->ite_list, &device->itt_head);
-
-	ite->collection = collection;
-	ite->lpi = lpi_nr;
-
 	if (its_is_collection_mapped(collection))
 		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
 
@@ -891,6 +904,26 @@ static void vgic_its_unmap_device(struct kvm *kvm, struct its_device *device)
 	kfree(device);
 }
 
+/* Must be called with its_lock mutex held */
+static struct its_device *vgic_its_alloc_device(struct vgic_its *its,
+						u32 device_id, gpa_t itt_addr,
+						u8 num_eventid_bits)
+{
+	struct its_device *device;
+
+	device = kzalloc(sizeof(*device), GFP_KERNEL);
+	if (!device)
+		return ERR_PTR(-ENOMEM);
+
+	device->device_id = device_id;
+	device->itt_addr = itt_addr;
+	device->num_eventid_bits = num_eventid_bits;
+	INIT_LIST_HEAD(&device->itt_head);
+
+	list_add_tail(&device->dev_list, &its->device_list);
+	return device;
+}
+
 /*
  * MAPD maps or unmaps a device ID to Interrupt Translation Tables (ITTs).
  * Must be called with the its_lock mutex held.
@@ -927,17 +960,10 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	if (!valid)
 		return 0;
 
-	device = kzalloc(sizeof(struct its_device), GFP_KERNEL);
-	if (!device)
-		return -ENOMEM;
-
-	device->device_id = device_id;
-	device->num_eventid_bits = num_eventid_bits;
-	device->itt_addr = itt_addr;
-
-	INIT_LIST_HEAD(&device->itt_head);
-
-	list_add_tail(&device->dev_list, &its->device_list);
+	device = vgic_its_alloc_device(its, device_id, itt_addr,
+				       num_eventid_bits);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
 
 	return 0;
 }
-- 
2.5.5

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

* [PATCH v7 18/24] KVM: arm64: vgic-its: Add infrastructure for table lookup
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

Add a generic scan_its_table() helper whose role consists in
scanning a contiguous table located in guest RAM and applying
a callback on each entry. Entries can be handled as linked lists
since the callback may return an id offset to the next entry and
also indicate whether the entry is the last one.

Helper functions also are added to compute the device/event ID
offset to the next DTE/ITE.

compute_next_devid_offset, compute_next_eventid_offset and
scan_table will become static in subsequent patches

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's R-b

v5 -> v6:
- add comments about 2d level table scan as suggested by Christoffer
- s/lookup_table/scan_its_table
- scan_table now return 0 if last elt found and +1 if not found
- use int for id
- simplify compute_next_devid/eventid_offset

v4 -> v5:
- use kvm_read_guest

v3 -> v4:
- remove static to avoid compilation warning
- correct size computation in looup_table()
- defines now encode the number of bits used for devid and eventid offsets
- use BIT() - 1 to encode the max offets
---
 virt/kvm/arm/vgic/vgic-its.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 737ba3c..d5c0057 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -244,6 +244,8 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 
 #define VITS_TYPER_IDBITS 16
 #define VITS_TYPER_DEVBITS 16
+#define VITS_DTE_MAX_DEVID_OFFSET	(BIT(14) - 1)
+#define VITS_ITE_MAX_EVENTID_OFFSET	(BIT(16) - 1)
 
 /*
  * Finds and returns a collection in the ITS collection table.
@@ -1728,6 +1730,96 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
+u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
+{
+	struct its_device *next;
+	u32 next_offset;
+
+	if (list_is_last(&dev->dev_list, h))
+		return 0;
+	next = list_next_entry(dev, dev_list);
+	next_offset = next->device_id - dev->device_id;
+
+	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
+}
+
+u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
+{
+	struct its_ite *next;
+	u32 next_offset;
+
+	if (list_is_last(&ite->ite_list, h))
+		return 0;
+	next = list_next_entry(ite, ite_list);
+	next_offset = next->event_id - ite->event_id;
+
+	return min_t(u32, next_offset, VITS_ITE_MAX_EVENTID_OFFSET);
+}
+
+/**
+ * entry_fn_t - Callback called on a table entry restore path
+ * @its: its handle
+ * @id: id of the entry
+ * @entry: pointer to the entry
+ * @opaque: pointer to an opaque data
+ *
+ * Return: < 0 on error, 0 if last element was identified, id offset to next
+ * element otherwise
+ */
+typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
+			  void *opaque);
+
+/**
+ * scan_its_table - Scan a contiguous table in guest RAM and applies a function
+ * to each entry
+ *
+ * @its: its handle
+ * @base: base gpa of the table
+ * @size: size of the table in bytes
+ * @esz: entry size in bytes
+ * @start_id: the ID of the first entry in the table
+ * (non zero for 2d level tables)
+ * @fn: function to apply on each entry
+ *
+ * Return: < 0 on error, 0 if last element was identified, 1 otherwise
+ * (the last element may not be found on second level tables)
+ */
+int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
+		   int start_id, entry_fn_t fn, void *opaque)
+{
+	void *entry = kzalloc(esz, GFP_KERNEL);
+	struct kvm *kvm = its->dev->kvm;
+	unsigned long len = size;
+	int id = start_id;
+	gpa_t gpa = base;
+	int ret;
+
+	while (len > 0) {
+		int next_offset;
+		size_t byte_offset;
+
+		ret = kvm_read_guest(kvm, gpa, entry, esz);
+		if (ret)
+			goto out;
+
+		next_offset = fn(its, id, entry, opaque);
+		if (next_offset <= 0) {
+			ret = next_offset;
+			goto out;
+		}
+
+		byte_offset = next_offset * esz;
+		id += next_offset;
+		gpa += byte_offset;
+		len -= byte_offset;
+	}
+	ret =  1;
+
+out:
+	kfree(entry);
+	return ret;
+}
+
 /**
  * vgic_its_save_device_tables - Save the device table and all ITT
  * into guest RAM
-- 
2.5.5

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

* [PATCH v7 18/24] KVM: arm64: vgic-its: Add infrastructure for table lookup
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Add a generic scan_its_table() helper whose role consists in
scanning a contiguous table located in guest RAM and applying
a callback on each entry. Entries can be handled as linked lists
since the callback may return an id offset to the next entry and
also indicate whether the entry is the last one.

Helper functions also are added to compute the device/event ID
offset to the next DTE/ITE.

compute_next_devid_offset, compute_next_eventid_offset and
scan_table will become static in subsequent patches

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's R-b

v5 -> v6:
- add comments about 2d level table scan as suggested by Christoffer
- s/lookup_table/scan_its_table
- scan_table now return 0 if last elt found and +1 if not found
- use int for id
- simplify compute_next_devid/eventid_offset

v4 -> v5:
- use kvm_read_guest

v3 -> v4:
- remove static to avoid compilation warning
- correct size computation in looup_table()
- defines now encode the number of bits used for devid and eventid offsets
- use BIT() - 1 to encode the max offets
---
 virt/kvm/arm/vgic/vgic-its.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 737ba3c..d5c0057 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -244,6 +244,8 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
 
 #define VITS_TYPER_IDBITS 16
 #define VITS_TYPER_DEVBITS 16
+#define VITS_DTE_MAX_DEVID_OFFSET	(BIT(14) - 1)
+#define VITS_ITE_MAX_EVENTID_OFFSET	(BIT(16) - 1)
 
 /*
  * Finds and returns a collection in the ITS collection table.
@@ -1728,6 +1730,96 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
+u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
+{
+	struct its_device *next;
+	u32 next_offset;
+
+	if (list_is_last(&dev->dev_list, h))
+		return 0;
+	next = list_next_entry(dev, dev_list);
+	next_offset = next->device_id - dev->device_id;
+
+	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
+}
+
+u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
+{
+	struct its_ite *next;
+	u32 next_offset;
+
+	if (list_is_last(&ite->ite_list, h))
+		return 0;
+	next = list_next_entry(ite, ite_list);
+	next_offset = next->event_id - ite->event_id;
+
+	return min_t(u32, next_offset, VITS_ITE_MAX_EVENTID_OFFSET);
+}
+
+/**
+ * entry_fn_t - Callback called on a table entry restore path
+ * @its: its handle
+ * @id: id of the entry
+ * @entry: pointer to the entry
+ * @opaque: pointer to an opaque data
+ *
+ * Return: < 0 on error, 0 if last element was identified, id offset to next
+ * element otherwise
+ */
+typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
+			  void *opaque);
+
+/**
+ * scan_its_table - Scan a contiguous table in guest RAM and applies a function
+ * to each entry
+ *
+ * @its: its handle
+ * @base: base gpa of the table
+ * @size: size of the table in bytes
+ * @esz: entry size in bytes
+ * @start_id: the ID of the first entry in the table
+ * (non zero for 2d level tables)
+ * @fn: function to apply on each entry
+ *
+ * Return: < 0 on error, 0 if last element was identified, 1 otherwise
+ * (the last element may not be found on second level tables)
+ */
+int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
+		   int start_id, entry_fn_t fn, void *opaque)
+{
+	void *entry = kzalloc(esz, GFP_KERNEL);
+	struct kvm *kvm = its->dev->kvm;
+	unsigned long len = size;
+	int id = start_id;
+	gpa_t gpa = base;
+	int ret;
+
+	while (len > 0) {
+		int next_offset;
+		size_t byte_offset;
+
+		ret = kvm_read_guest(kvm, gpa, entry, esz);
+		if (ret)
+			goto out;
+
+		next_offset = fn(its, id, entry, opaque);
+		if (next_offset <= 0) {
+			ret = next_offset;
+			goto out;
+		}
+
+		byte_offset = next_offset * esz;
+		id += next_offset;
+		gpa += byte_offset;
+		len -= byte_offset;
+	}
+	ret =  1;
+
+out:
+	kfree(entry);
+	return ret;
+}
+
 /**
  * vgic_its_save_device_tables - Save the device table and all ITT
  * into guest RAM
-- 
2.5.5

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

* [PATCH v7 19/24] KVM: arm64: vgic-its: Collection table save/restore
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

The save path copies the collection entries into guest RAM
at the GPA specified in the BASER register. This obviously
requires the BASER to be set. The last written element is a
dummy collection table entry.

We do not index by collection ID as the collection entry
can fit into 8 bytes while containing the collection ID.

On restore path we re-allocate the collection objects.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's R-b
- remove filled == max_size check

v5 -> v6:
- remove the valid pointer from vgic_its_restore_cte and
  return +1 if no error and last elt not found
- check the BASER valid bit
- add BUG_ON to check esz versus val size

v4 -> v5:
- add macros for field encoding/decoding
- use abi->cte_esz
- rename flush into save
- check the target_addr is valid

v3 -> v4:
- replaced u64 *ptr by gpa_t gpa
- check the collection does not exist before allocating it

v1 -> v2:
- reword commit message and directly use 8 as entry size
- no kvm parameter anymore
- add helper for flush/restore cte
- table size computed here
- add le64/cpu conversions
---
 virt/kvm/arm/vgic/vgic-its.c | 100 ++++++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic.h     |   9 ++++
 2 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index d5c0057..5523f0a 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1838,13 +1838,89 @@ static int vgic_its_restore_device_tables(struct vgic_its *its)
 	return -ENXIO;
 }
 
+static int vgic_its_save_cte(struct vgic_its *its,
+			     struct its_collection *collection,
+			     gpa_t gpa, int esz)
+{
+	u64 val;
+
+	val = (1ULL << KVM_ITS_CTE_VALID_SHIFT |
+	       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
+	       collection->collection_id);
+	val = cpu_to_le64(val);
+	return kvm_write_guest(its->dev->kvm, gpa, &val, esz);
+}
+
+static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
+{
+	struct its_collection *collection;
+	struct kvm *kvm = its->dev->kvm;
+	u32 target_addr, coll_id;
+	u64 val;
+	int ret;
+
+	BUG_ON(esz > sizeof(val));
+	ret = kvm_read_guest(kvm, gpa, &val, esz);
+	if (ret)
+		return ret;
+	val = le64_to_cpu(val);
+	if (!(val & KVM_ITS_CTE_VALID_MASK))
+		return 0;
+
+	target_addr = (u32)(val >> KVM_ITS_CTE_RDBASE_SHIFT);
+	coll_id = val & KVM_ITS_CTE_ICID_MASK;
+
+	if (target_addr >= atomic_read(&kvm->online_vcpus))
+		return -EINVAL;
+
+	collection = find_collection(its, coll_id);
+	if (collection)
+		return -EEXIST;
+	ret = vgic_its_alloc_collection(its, &collection, coll_id);
+	if (ret)
+		return ret;
+	collection->target_addr = target_addr;
+	return 1;
+}
+
 /**
  * vgic_its_save_collection_table - Save the collection table into
  * guest RAM
  */
 static int vgic_its_save_collection_table(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	struct its_collection *collection;
+	u64 val;
+	gpa_t gpa;
+	size_t max_size, filled = 0;
+	int ret, cte_esz = abi->cte_esz;
+
+	gpa = BASER_ADDRESS(its->baser_coll_table);
+	if (!gpa)
+		return 0;
+
+	max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K;
+
+	list_for_each_entry(collection, &its->collection_list, coll_list) {
+		ret = vgic_its_save_cte(its, collection, gpa, cte_esz);
+		if (ret)
+			return ret;
+		gpa += cte_esz;
+		filled += cte_esz;
+	}
+
+	if (filled == max_size)
+		return 0;
+
+	/*
+	 * table is not fully filled, add a last dummy element
+	 * with valid bit unset
+	 */
+	val = 0;
+	BUG_ON(cte_esz > sizeof(val));
+	ret = kvm_write_guest(its->dev->kvm, gpa, &val, cte_esz);
+	return ret;
 }
 
 /**
@@ -1854,7 +1930,27 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
  */
 static int vgic_its_restore_collection_table(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	int cte_esz = abi->cte_esz;
+	size_t max_size, read = 0;
+	gpa_t gpa;
+	int ret;
+
+	if (!(its->baser_coll_table & GITS_BASER_VALID))
+		return 0;
+
+	gpa = BASER_ADDRESS(its->baser_coll_table);
+
+	max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K;
+
+	while (read < max_size) {
+		ret = vgic_its_restore_cte(its, gpa, cte_esz);
+		if (ret <= 0)
+			break;
+		gpa += cte_esz;
+		read += cte_esz;
+	}
+	return ret;
 }
 
 /**
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 309ab64..58adcae 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -73,6 +73,15 @@
 				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
 				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
 
+/*
+ * As per Documentation/virtual/kvm/devices/arm-vgic-its.txt,
+ * below macros are defined for ITS table entry encoding.
+ */
+#define KVM_ITS_CTE_VALID_SHIFT		63
+#define KVM_ITS_CTE_VALID_MASK		BIT_ULL(63)
+#define KVM_ITS_CTE_RDBASE_SHIFT	16
+#define KVM_ITS_CTE_ICID_MASK		GENMASK_ULL(15, 0)
+
 static inline bool irq_is_pending(struct vgic_irq *irq)
 {
 	if (irq->config == VGIC_CONFIG_EDGE)
-- 
2.5.5

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

* [PATCH v7 19/24] KVM: arm64: vgic-its: Collection table save/restore
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

The save path copies the collection entries into guest RAM
at the GPA specified in the BASER register. This obviously
requires the BASER to be set. The last written element is a
dummy collection table entry.

We do not index by collection ID as the collection entry
can fit into 8 bytes while containing the collection ID.

On restore path we re-allocate the collection objects.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's R-b
- remove filled == max_size check

v5 -> v6:
- remove the valid pointer from vgic_its_restore_cte and
  return +1 if no error and last elt not found
- check the BASER valid bit
- add BUG_ON to check esz versus val size

v4 -> v5:
- add macros for field encoding/decoding
- use abi->cte_esz
- rename flush into save
- check the target_addr is valid

v3 -> v4:
- replaced u64 *ptr by gpa_t gpa
- check the collection does not exist before allocating it

v1 -> v2:
- reword commit message and directly use 8 as entry size
- no kvm parameter anymore
- add helper for flush/restore cte
- table size computed here
- add le64/cpu conversions
---
 virt/kvm/arm/vgic/vgic-its.c | 100 ++++++++++++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic.h     |   9 ++++
 2 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index d5c0057..5523f0a 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1838,13 +1838,89 @@ static int vgic_its_restore_device_tables(struct vgic_its *its)
 	return -ENXIO;
 }
 
+static int vgic_its_save_cte(struct vgic_its *its,
+			     struct its_collection *collection,
+			     gpa_t gpa, int esz)
+{
+	u64 val;
+
+	val = (1ULL << KVM_ITS_CTE_VALID_SHIFT |
+	       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
+	       collection->collection_id);
+	val = cpu_to_le64(val);
+	return kvm_write_guest(its->dev->kvm, gpa, &val, esz);
+}
+
+static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
+{
+	struct its_collection *collection;
+	struct kvm *kvm = its->dev->kvm;
+	u32 target_addr, coll_id;
+	u64 val;
+	int ret;
+
+	BUG_ON(esz > sizeof(val));
+	ret = kvm_read_guest(kvm, gpa, &val, esz);
+	if (ret)
+		return ret;
+	val = le64_to_cpu(val);
+	if (!(val & KVM_ITS_CTE_VALID_MASK))
+		return 0;
+
+	target_addr = (u32)(val >> KVM_ITS_CTE_RDBASE_SHIFT);
+	coll_id = val & KVM_ITS_CTE_ICID_MASK;
+
+	if (target_addr >= atomic_read(&kvm->online_vcpus))
+		return -EINVAL;
+
+	collection = find_collection(its, coll_id);
+	if (collection)
+		return -EEXIST;
+	ret = vgic_its_alloc_collection(its, &collection, coll_id);
+	if (ret)
+		return ret;
+	collection->target_addr = target_addr;
+	return 1;
+}
+
 /**
  * vgic_its_save_collection_table - Save the collection table into
  * guest RAM
  */
 static int vgic_its_save_collection_table(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	struct its_collection *collection;
+	u64 val;
+	gpa_t gpa;
+	size_t max_size, filled = 0;
+	int ret, cte_esz = abi->cte_esz;
+
+	gpa = BASER_ADDRESS(its->baser_coll_table);
+	if (!gpa)
+		return 0;
+
+	max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K;
+
+	list_for_each_entry(collection, &its->collection_list, coll_list) {
+		ret = vgic_its_save_cte(its, collection, gpa, cte_esz);
+		if (ret)
+			return ret;
+		gpa += cte_esz;
+		filled += cte_esz;
+	}
+
+	if (filled == max_size)
+		return 0;
+
+	/*
+	 * table is not fully filled, add a last dummy element
+	 * with valid bit unset
+	 */
+	val = 0;
+	BUG_ON(cte_esz > sizeof(val));
+	ret = kvm_write_guest(its->dev->kvm, gpa, &val, cte_esz);
+	return ret;
 }
 
 /**
@@ -1854,7 +1930,27 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
  */
 static int vgic_its_restore_collection_table(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	int cte_esz = abi->cte_esz;
+	size_t max_size, read = 0;
+	gpa_t gpa;
+	int ret;
+
+	if (!(its->baser_coll_table & GITS_BASER_VALID))
+		return 0;
+
+	gpa = BASER_ADDRESS(its->baser_coll_table);
+
+	max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K;
+
+	while (read < max_size) {
+		ret = vgic_its_restore_cte(its, gpa, cte_esz);
+		if (ret <= 0)
+			break;
+		gpa += cte_esz;
+		read += cte_esz;
+	}
+	return ret;
 }
 
 /**
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 309ab64..58adcae 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -73,6 +73,15 @@
 				      KVM_REG_ARM_VGIC_SYSREG_CRM_MASK | \
 				      KVM_REG_ARM_VGIC_SYSREG_OP2_MASK)
 
+/*
+ * As per Documentation/virtual/kvm/devices/arm-vgic-its.txt,
+ * below macros are defined for ITS table entry encoding.
+ */
+#define KVM_ITS_CTE_VALID_SHIFT		63
+#define KVM_ITS_CTE_VALID_MASK		BIT_ULL(63)
+#define KVM_ITS_CTE_RDBASE_SHIFT	16
+#define KVM_ITS_CTE_ICID_MASK		GENMASK_ULL(15, 0)
+
 static inline bool irq_is_pending(struct vgic_irq *irq)
 {
 	if (irq->config == VGIC_CONFIG_EDGE)
-- 
2.5.5

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

* [PATCH v7 20/24] KVM: arm64: vgic-its: vgic_its_check_id returns the entry's GPA
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, quintela, dgilbert, bjsprakash.linux, pbonzini

As vgic_its_check_id() computes the device/collection entry's
GPA, let's return it so that new callers can retrieve it easily.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v5 -> v6:
- add Christoffer's A-b

v3 -> v4:
- check eaddr is not NULL to allow passing NULL eaddr parameter
  to vgic_its_check_id

v2: new
---
 virt/kvm/arm/vgic/vgic-its.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 5523f0a..90afc83 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -694,7 +694,8 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
  * is actually valid (covered by a memslot and guest accessible).
  * For this we have to read the respective first level entry.
  */
-static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
+static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id,
+			      gpa_t *eaddr)
 {
 	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
 	u64 indirect_ptr, type = GITS_BASER_TYPE(baser);
@@ -725,6 +726,8 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
 		addr = BASER_ADDRESS(baser) + id * esz;
 		gfn = addr >> PAGE_SHIFT;
 
+		if (eaddr)
+			*eaddr = addr;
 		return kvm_is_visible_gfn(its->dev->kvm, gfn);
 	}
 
@@ -757,6 +760,8 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
 	indirect_ptr += index * esz;
 	gfn = indirect_ptr >> PAGE_SHIFT;
 
+	if (eaddr)
+		*eaddr = indirect_ptr;
 	return kvm_is_visible_gfn(its->dev->kvm, gfn);
 }
 
@@ -766,7 +771,7 @@ static int vgic_its_alloc_collection(struct vgic_its *its,
 {
 	struct its_collection *collection;
 
-	if (!vgic_its_check_id(its, its->baser_coll_table, coll_id))
+	if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
 		return E_ITS_MAPC_COLLECTION_OOR;
 
 	collection = kzalloc(sizeof(*collection), GFP_KERNEL);
@@ -939,7 +944,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
 	struct its_device *device;
 
-	if (!vgic_its_check_id(its, its->baser_device_table, device_id))
+	if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL))
 		return E_ITS_MAPD_DEVICE_OOR;
 
 	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
-- 
2.5.5

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

* [PATCH v7 20/24] KVM: arm64: vgic-its: vgic_its_check_id returns the entry's GPA
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

As vgic_its_check_id() computes the device/collection entry's
GPA, let's return it so that new callers can retrieve it easily.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Acked-by: Christoffer Dall <cdall@linaro.org>

---
v5 -> v6:
- add Christoffer's A-b

v3 -> v4:
- check eaddr is not NULL to allow passing NULL eaddr parameter
  to vgic_its_check_id

v2: new
---
 virt/kvm/arm/vgic/vgic-its.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 5523f0a..90afc83 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -694,7 +694,8 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its,
  * is actually valid (covered by a memslot and guest accessible).
  * For this we have to read the respective first level entry.
  */
-static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
+static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id,
+			      gpa_t *eaddr)
 {
 	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
 	u64 indirect_ptr, type = GITS_BASER_TYPE(baser);
@@ -725,6 +726,8 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
 		addr = BASER_ADDRESS(baser) + id * esz;
 		gfn = addr >> PAGE_SHIFT;
 
+		if (eaddr)
+			*eaddr = addr;
 		return kvm_is_visible_gfn(its->dev->kvm, gfn);
 	}
 
@@ -757,6 +760,8 @@ static bool vgic_its_check_id(struct vgic_its *its, u64 baser, u32 id)
 	indirect_ptr += index * esz;
 	gfn = indirect_ptr >> PAGE_SHIFT;
 
+	if (eaddr)
+		*eaddr = indirect_ptr;
 	return kvm_is_visible_gfn(its->dev->kvm, gfn);
 }
 
@@ -766,7 +771,7 @@ static int vgic_its_alloc_collection(struct vgic_its *its,
 {
 	struct its_collection *collection;
 
-	if (!vgic_its_check_id(its, its->baser_coll_table, coll_id))
+	if (!vgic_its_check_id(its, its->baser_coll_table, coll_id, NULL))
 		return E_ITS_MAPC_COLLECTION_OOR;
 
 	collection = kzalloc(sizeof(*collection), GFP_KERNEL);
@@ -939,7 +944,7 @@ static int vgic_its_cmd_handle_mapd(struct kvm *kvm, struct vgic_its *its,
 	gpa_t itt_addr = its_cmd_get_ittaddr(its_cmd);
 	struct its_device *device;
 
-	if (!vgic_its_check_id(its, its->baser_device_table, device_id))
+	if (!vgic_its_check_id(its, its->baser_device_table, device_id, NULL))
 		return E_ITS_MAPD_DEVICE_OOR;
 
 	if (valid && num_eventid_bits > VITS_TYPER_IDBITS)
-- 
2.5.5

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

* [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

This patch saves the device table entries into guest RAM.
Both flat table and 2 stage tables are supported. DeviceId
indexing is used.

For each device listed in the device table, we also save
the translation table using the vgic_its_save/restore_itt
routines. Those functions will be implemented in a subsequent
patch.

On restore, devices are re-allocated and their itt are
re-built.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v5 -> v6:
- accomodate vgic_its_alloc_device change of proto
- define bit fields for L1 entries
- s/handle_l1_entry/handle_l1_dte
- s/ite_esz/dte_esz in handle_l1_dte
- check BASER valid bit
- s/nb_eventid_bits/num_eventid_bits
- new convention for returned values
- itt functions implemented in subsequent patch

v4 -> v5:
- sort the device list by deviceid on device table save
- use defines for shifts and masks
- use abi->dte_esz
- clatify entry sizes for L1 and L2 tables

v3 -> v4:
- use the new proto for its_alloc_device
- compute_next_devid_offset, vgic_its_flush/restore_itt
  become static in this patch
- change in the DTE entry format with the introduction of the
  valid bit and next field width decrease; ittaddr encoded
  on its full range
- fix handle_l1_entry entry handling
- correct vgic_its_table_restore error handling

v2 -> v3:
- fix itt_addr bitmask in vgic_its_restore_dte
- addition of return 0 in vgic_its_restore_ite moved to
  the ITE related patch

v1 -> v2:
- use 8 byte format for DTE and ITE
- support 2 stage format
- remove kvm parameter
- ITT flush/restore moved in a separate patch
- use deviceid indexing
---
 virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.h     |  10 +++
 2 files changed, 199 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 90afc83..3dea626 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/uaccess.h>
+#include <linux/list_sort.h>
 
 #include <linux/irqchip/arm-gic-v3.h>
 
@@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
-u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
+static u32 compute_next_devid_offset(struct list_head *h,
+				     struct its_device *dev)
 {
 	struct its_device *next;
 	u32 next_offset;
@@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
  * Return: < 0 on error, 0 if last element was identified, 1 otherwise
  * (the last element may not be found on second level tables)
  */
-int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
-		   int start_id, entry_fn_t fn, void *opaque)
+static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
+			  int start_id, entry_fn_t fn, void *opaque)
 {
 	void *entry = kzalloc(esz, GFP_KERNEL);
 	struct kvm *kvm = its->dev->kvm;
@@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
 	return ret;
 }
 
+static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
+{
+	return -ENXIO;
+}
+
+static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_save_dte - Save a device table entry at a given GPA
+ *
+ * @its: ITS handle
+ * @dev: ITS device
+ * @ptr: GPA
+ */
+static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
+			     gpa_t ptr, int dte_esz)
+{
+	struct kvm *kvm = its->dev->kvm;
+	u64 val, itt_addr_field;
+	u32 next_offset;
+
+	itt_addr_field = dev->itt_addr >> 8;
+	next_offset = compute_next_devid_offset(&its->device_list, dev);
+	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
+	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
+	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
+		(dev->num_eventid_bits - 1));
+	val = cpu_to_le64(val);
+	return kvm_write_guest(kvm, ptr, &val, dte_esz);
+}
+
+/**
+ * vgic_its_restore_dte - restore a device table entry
+ *
+ * @its: its handle
+ * @id: device id the DTE corresponds to
+ * @ptr: kernel VA where the 8 byte DTE is located
+ * @opaque: unused
+ *
+ * Return: < 0 on error, 0 if the dte is the last one, id offset to the
+ * next dte otherwise
+ */
+static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
+				void *ptr, void *opaque)
+{
+	struct its_device *dev;
+	gpa_t itt_addr;
+	u8 num_eventid_bits;
+	u64 entry = *(u64 *)ptr;
+	bool valid;
+	u32 offset;
+	int ret;
+
+	entry = le64_to_cpu(entry);
+
+	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
+	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
+	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
+			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
+
+	if (!valid)
+		return 1;
+
+	/* dte entry is valid */
+	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
+
+	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	ret = vgic_its_restore_itt(its, dev);
+	if (ret)
+		return ret;
+
+	return offset;
+}
+
+static int vgic_its_device_cmp(void *priv, struct list_head *a,
+			       struct list_head *b)
+{
+	struct its_device *deva = container_of(a, struct its_device, dev_list);
+	struct its_device *devb = container_of(b, struct its_device, dev_list);
+
+	if (deva->device_id < devb->device_id)
+		return -1;
+	else
+		return 1;
+}
+
 /**
  * vgic_its_save_device_tables - Save the device table and all ITT
  * into guest RAM
+ *
+ * L1/L2 handling is hidden by vgic_its_check_id() helper which directly
+ * returns the GPA of the device entry
  */
 static int vgic_its_save_device_tables(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	struct its_device *dev;
+	int dte_esz = abi->dte_esz;
+	u64 baser;
+
+	baser = its->baser_device_table;
+
+	list_sort(NULL, &its->device_list, vgic_its_device_cmp);
+
+	list_for_each_entry(dev, &its->device_list, dev_list) {
+		int ret;
+		gpa_t eaddr;
+
+		if (!vgic_its_check_id(its, baser,
+				       dev->device_id, &eaddr))
+			return -EINVAL;
+
+		ret = vgic_its_save_itt(its, dev);
+		if (ret)
+			return ret;
+
+		ret = vgic_its_save_dte(its, dev, eaddr, dte_esz);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+/**
+ * handle_l1_dte - callback used for L1 device table entries (2 stage case)
+ *
+ * @its: its handle
+ * @id: index of the entry in the L1 table
+ * @addr: kernel VA
+ * @opaque: unused
+ *
+ * L1 table entries are scanned by steps of 1 entry
+ * Return < 0 if error, 0 if last dte was found when scanning the L2
+ * table, +1 otherwise (meaning next L1 entry must be scanned)
+ */
+static int handle_l1_dte(struct vgic_its *its, u32 id, void *addr,
+			 void *opaque)
+{
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	int l2_start_id = id * (SZ_64K / abi->dte_esz);
+	u64 entry = *(u64 *)addr;
+	int dte_esz = abi->dte_esz;
+	gpa_t gpa;
+	int ret;
+
+	entry = le64_to_cpu(entry);
+
+	if (!(entry & KVM_ITS_L1E_VALID_MASK))
+		return 1;
+
+	gpa = entry & KVM_ITS_L1E_ADDR_MASK;
+
+	ret = scan_its_table(its, gpa, SZ_64K, dte_esz,
+			     l2_start_id, vgic_its_restore_dte, NULL);
+
+	if (ret <= 0)
+		return ret;
+
+	return 1;
 }
 
 /**
@@ -1840,7 +2000,31 @@ static int vgic_its_save_device_tables(struct vgic_its *its)
  */
 static int vgic_its_restore_device_tables(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	u64 baser = its->baser_device_table;
+	int l1_esz, ret;
+	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
+	gpa_t l1_gpa;
+
+	if (!(baser & GITS_BASER_VALID))
+		return 0;
+
+	l1_gpa = BASER_ADDRESS(baser);
+
+	if (baser & GITS_BASER_INDIRECT) {
+		l1_esz = GITS_LVL1_ENTRY_SIZE;
+		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
+				     handle_l1_dte, NULL);
+	} else {
+		l1_esz = abi->dte_esz;
+		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
+				     vgic_its_restore_dte, NULL);
+	}
+
+	if (ret > 0)
+		ret = -EINVAL;
+
+	return ret;
 }
 
 static int vgic_its_save_cte(struct vgic_its *its,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 58adcae..e896114 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -81,6 +81,16 @@
 #define KVM_ITS_CTE_VALID_MASK		BIT_ULL(63)
 #define KVM_ITS_CTE_RDBASE_SHIFT	16
 #define KVM_ITS_CTE_ICID_MASK		GENMASK_ULL(15, 0)
+#define KVM_ITS_DTE_VALID_SHIFT		63
+#define KVM_ITS_DTE_VALID_MASK		BIT_ULL(63)
+#define KVM_ITS_DTE_NEXT_SHIFT		49
+#define KVM_ITS_DTE_NEXT_MASK		GENMASK_ULL(62, 49)
+#define KVM_ITS_DTE_ITTADDR_SHIFT	5
+#define KVM_ITS_DTE_ITTADDR_MASK	GENMASK_ULL(48, 5)
+#define KVM_ITS_DTE_SIZE_MASK		GENMASK_ULL(4, 0)
+#define KVM_ITS_L1E_VALID_MASK		BIT_ULL(63)
+/* we only support 64 kB translation table page size */
+#define KVM_ITS_L1E_ADDR_MASK		GENMASK_ULL(51, 16)
 
 static inline bool irq_is_pending(struct vgic_irq *irq)
 {
-- 
2.5.5

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

* [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

This patch saves the device table entries into guest RAM.
Both flat table and 2 stage tables are supported. DeviceId
indexing is used.

For each device listed in the device table, we also save
the translation table using the vgic_its_save/restore_itt
routines. Those functions will be implemented in a subsequent
patch.

On restore, devices are re-allocated and their itt are
re-built.

Signed-off-by: Eric Auger <eric.auger@redhat.com>

---
v5 -> v6:
- accomodate vgic_its_alloc_device change of proto
- define bit fields for L1 entries
- s/handle_l1_entry/handle_l1_dte
- s/ite_esz/dte_esz in handle_l1_dte
- check BASER valid bit
- s/nb_eventid_bits/num_eventid_bits
- new convention for returned values
- itt functions implemented in subsequent patch

v4 -> v5:
- sort the device list by deviceid on device table save
- use defines for shifts and masks
- use abi->dte_esz
- clatify entry sizes for L1 and L2 tables

v3 -> v4:
- use the new proto for its_alloc_device
- compute_next_devid_offset, vgic_its_flush/restore_itt
  become static in this patch
- change in the DTE entry format with the introduction of the
  valid bit and next field width decrease; ittaddr encoded
  on its full range
- fix handle_l1_entry entry handling
- correct vgic_its_table_restore error handling

v2 -> v3:
- fix itt_addr bitmask in vgic_its_restore_dte
- addition of return 0 in vgic_its_restore_ite moved to
  the ITE related patch

v1 -> v2:
- use 8 byte format for DTE and ITE
- support 2 stage format
- remove kvm parameter
- ITT flush/restore moved in a separate patch
- use deviceid indexing
---
 virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.h     |  10 +++
 2 files changed, 199 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 90afc83..3dea626 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/uaccess.h>
+#include <linux/list_sort.h>
 
 #include <linux/irqchip/arm-gic-v3.h>
 
@@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
-u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
+static u32 compute_next_devid_offset(struct list_head *h,
+				     struct its_device *dev)
 {
 	struct its_device *next;
 	u32 next_offset;
@@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
  * Return: < 0 on error, 0 if last element was identified, 1 otherwise
  * (the last element may not be found on second level tables)
  */
-int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
-		   int start_id, entry_fn_t fn, void *opaque)
+static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
+			  int start_id, entry_fn_t fn, void *opaque)
 {
 	void *entry = kzalloc(esz, GFP_KERNEL);
 	struct kvm *kvm = its->dev->kvm;
@@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
 	return ret;
 }
 
+static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
+{
+	return -ENXIO;
+}
+
+static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
+{
+	return -ENXIO;
+}
+
+/**
+ * vgic_its_save_dte - Save a device table entry at a given GPA
+ *
+ * @its: ITS handle
+ * @dev: ITS device
+ * @ptr: GPA
+ */
+static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
+			     gpa_t ptr, int dte_esz)
+{
+	struct kvm *kvm = its->dev->kvm;
+	u64 val, itt_addr_field;
+	u32 next_offset;
+
+	itt_addr_field = dev->itt_addr >> 8;
+	next_offset = compute_next_devid_offset(&its->device_list, dev);
+	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
+	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
+	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
+		(dev->num_eventid_bits - 1));
+	val = cpu_to_le64(val);
+	return kvm_write_guest(kvm, ptr, &val, dte_esz);
+}
+
+/**
+ * vgic_its_restore_dte - restore a device table entry
+ *
+ * @its: its handle
+ * @id: device id the DTE corresponds to
+ * @ptr: kernel VA where the 8 byte DTE is located
+ * @opaque: unused
+ *
+ * Return: < 0 on error, 0 if the dte is the last one, id offset to the
+ * next dte otherwise
+ */
+static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
+				void *ptr, void *opaque)
+{
+	struct its_device *dev;
+	gpa_t itt_addr;
+	u8 num_eventid_bits;
+	u64 entry = *(u64 *)ptr;
+	bool valid;
+	u32 offset;
+	int ret;
+
+	entry = le64_to_cpu(entry);
+
+	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
+	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
+	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
+			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
+
+	if (!valid)
+		return 1;
+
+	/* dte entry is valid */
+	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
+
+	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	ret = vgic_its_restore_itt(its, dev);
+	if (ret)
+		return ret;
+
+	return offset;
+}
+
+static int vgic_its_device_cmp(void *priv, struct list_head *a,
+			       struct list_head *b)
+{
+	struct its_device *deva = container_of(a, struct its_device, dev_list);
+	struct its_device *devb = container_of(b, struct its_device, dev_list);
+
+	if (deva->device_id < devb->device_id)
+		return -1;
+	else
+		return 1;
+}
+
 /**
  * vgic_its_save_device_tables - Save the device table and all ITT
  * into guest RAM
+ *
+ * L1/L2 handling is hidden by vgic_its_check_id() helper which directly
+ * returns the GPA of the device entry
  */
 static int vgic_its_save_device_tables(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	struct its_device *dev;
+	int dte_esz = abi->dte_esz;
+	u64 baser;
+
+	baser = its->baser_device_table;
+
+	list_sort(NULL, &its->device_list, vgic_its_device_cmp);
+
+	list_for_each_entry(dev, &its->device_list, dev_list) {
+		int ret;
+		gpa_t eaddr;
+
+		if (!vgic_its_check_id(its, baser,
+				       dev->device_id, &eaddr))
+			return -EINVAL;
+
+		ret = vgic_its_save_itt(its, dev);
+		if (ret)
+			return ret;
+
+		ret = vgic_its_save_dte(its, dev, eaddr, dte_esz);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+/**
+ * handle_l1_dte - callback used for L1 device table entries (2 stage case)
+ *
+ * @its: its handle
+ * @id: index of the entry in the L1 table
+ * @addr: kernel VA
+ * @opaque: unused
+ *
+ * L1 table entries are scanned by steps of 1 entry
+ * Return < 0 if error, 0 if last dte was found when scanning the L2
+ * table, +1 otherwise (meaning next L1 entry must be scanned)
+ */
+static int handle_l1_dte(struct vgic_its *its, u32 id, void *addr,
+			 void *opaque)
+{
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	int l2_start_id = id * (SZ_64K / abi->dte_esz);
+	u64 entry = *(u64 *)addr;
+	int dte_esz = abi->dte_esz;
+	gpa_t gpa;
+	int ret;
+
+	entry = le64_to_cpu(entry);
+
+	if (!(entry & KVM_ITS_L1E_VALID_MASK))
+		return 1;
+
+	gpa = entry & KVM_ITS_L1E_ADDR_MASK;
+
+	ret = scan_its_table(its, gpa, SZ_64K, dte_esz,
+			     l2_start_id, vgic_its_restore_dte, NULL);
+
+	if (ret <= 0)
+		return ret;
+
+	return 1;
 }
 
 /**
@@ -1840,7 +2000,31 @@ static int vgic_its_save_device_tables(struct vgic_its *its)
  */
 static int vgic_its_restore_device_tables(struct vgic_its *its)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	u64 baser = its->baser_device_table;
+	int l1_esz, ret;
+	int l1_tbl_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
+	gpa_t l1_gpa;
+
+	if (!(baser & GITS_BASER_VALID))
+		return 0;
+
+	l1_gpa = BASER_ADDRESS(baser);
+
+	if (baser & GITS_BASER_INDIRECT) {
+		l1_esz = GITS_LVL1_ENTRY_SIZE;
+		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
+				     handle_l1_dte, NULL);
+	} else {
+		l1_esz = abi->dte_esz;
+		ret = scan_its_table(its, l1_gpa, l1_tbl_size, l1_esz, 0,
+				     vgic_its_restore_dte, NULL);
+	}
+
+	if (ret > 0)
+		ret = -EINVAL;
+
+	return ret;
 }
 
 static int vgic_its_save_cte(struct vgic_its *its,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 58adcae..e896114 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -81,6 +81,16 @@
 #define KVM_ITS_CTE_VALID_MASK		BIT_ULL(63)
 #define KVM_ITS_CTE_RDBASE_SHIFT	16
 #define KVM_ITS_CTE_ICID_MASK		GENMASK_ULL(15, 0)
+#define KVM_ITS_DTE_VALID_SHIFT		63
+#define KVM_ITS_DTE_VALID_MASK		BIT_ULL(63)
+#define KVM_ITS_DTE_NEXT_SHIFT		49
+#define KVM_ITS_DTE_NEXT_MASK		GENMASK_ULL(62, 49)
+#define KVM_ITS_DTE_ITTADDR_SHIFT	5
+#define KVM_ITS_DTE_ITTADDR_MASK	GENMASK_ULL(48, 5)
+#define KVM_ITS_DTE_SIZE_MASK		GENMASK_ULL(4, 0)
+#define KVM_ITS_L1E_VALID_MASK		BIT_ULL(63)
+/* we only support 64 kB translation table page size */
+#define KVM_ITS_L1E_ADDR_MASK		GENMASK_ULL(51, 16)
 
 static inline bool irq_is_pending(struct vgic_irq *irq)
 {
-- 
2.5.5

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

* [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

Implement routines to save and restore device ITT and their
interrupt table entries (ITE).

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's R-b

v5 -> v6:
- accomodate vgic_its_alloc_ite change of proto
- check LPI ID on restore, check eventid offset
- initializations on separate line
- coming after device save/restore
- add_lpi does config and pending bit sync

v4 -> v5:
- ITE are now sorted by eventid on the flush
- rename *flush* into *save*
- use macros for shits and masks
- pass ite_esz to vgic_its_save_ite

v3 -> v4:
- lookup_table and compute_next_eventid_offset become static in this
  patch
- remove static along with vgic_its_flush/restore_itt to avoid
  compilation warnings
- next field only computed with a shift (mask removed)
- handle the case where the last element has not been found

v2 -> v3:
- add return 0 in vgic_its_restore_ite (was in subsequent patch)

v2: creation
---
 virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.h     |   4 ++
 2 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 3dea626..adb3d9e 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
 	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
 }
 
-u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
+static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
 {
 	struct its_ite *next;
 	u32 next_offset;
@@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
 	return ret;
 }
 
+/**
+ * vgic_its_save_ite - Save an interrupt translation entry at @gpa
+ */
+static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
+			      struct its_ite *ite, gpa_t gpa, int ite_esz)
+{
+	struct kvm *kvm = its->dev->kvm;
+	u32 next_offset;
+	u64 val;
+
+	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
+	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
+	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
+		ite->collection->collection_id;
+	val = cpu_to_le64(val);
+	return kvm_write_guest(kvm, gpa, &val, ite_esz);
+}
+
+/**
+ * vgic_its_restore_ite - restore an interrupt translation entry
+ * @event_id: id used for indexing
+ * @ptr: pointer to the ITE entry
+ * @opaque: pointer to the its_device
+ */
+static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
+				void *ptr, void *opaque)
+{
+	struct its_device *dev = (struct its_device *)opaque;
+	struct its_collection *collection;
+	struct kvm *kvm = its->dev->kvm;
+	struct kvm_vcpu *vcpu = NULL;
+	u64 val;
+	u64 *p = (u64 *)ptr;
+	struct vgic_irq *irq;
+	u32 coll_id, lpi_id;
+	struct its_ite *ite;
+	u32 offset;
+
+	val = *p;
+
+	val = le64_to_cpu(val);
+
+	coll_id = val & KVM_ITS_ITE_ICID_MASK;
+	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
+
+	if (!lpi_id)
+		return 1; /* invalid entry, no choice but to scan next entry */
+
+	if (lpi_id < VGIC_MIN_LPI)
+		return -EINVAL;
+
+	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
+	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
+		return -EINVAL;
+
+	collection = find_collection(its, coll_id);
+	if (!collection)
+		return -EINVAL;
+
+	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
+	if (IS_ERR(ite))
+		return PTR_ERR(ite);
+
+	if (its_is_collection_mapped(collection))
+		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
+
+	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
+	if (IS_ERR(irq))
+		return PTR_ERR(irq);
+	ite->irq = irq;
+
+	return offset;
+}
+
+static int vgic_its_ite_cmp(void *priv, struct list_head *a,
+			    struct list_head *b)
+{
+	struct its_ite *itea = container_of(a, struct its_ite, ite_list);
+	struct its_ite *iteb = container_of(b, struct its_ite, ite_list);
+
+	if (itea->event_id < iteb->event_id)
+		return -1;
+	else
+		return 1;
+}
+
 static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	gpa_t base = device->itt_addr;
+	struct its_ite *ite;
+	int ret;
+	int ite_esz = abi->ite_esz;
+
+	list_sort(NULL, &device->itt_head, vgic_its_ite_cmp);
+
+	list_for_each_entry(ite, &device->itt_head, ite_list) {
+		gpa_t gpa = base + ite->event_id * ite_esz;
+
+		ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz);
+		if (ret)
+			return ret;
+	}
+	return 0;
 }
 
 static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	gpa_t base = dev->itt_addr;
+	int ret;
+	int ite_esz = abi->ite_esz;
+	size_t max_size = BIT_ULL(dev->num_eventid_bits) * ite_esz;
+
+	ret = scan_its_table(its, base, max_size, ite_esz, 0,
+			     vgic_its_restore_ite, dev);
+
+	return ret;
 }
 
 /**
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e896114..92a8ca0 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -81,6 +81,10 @@
 #define KVM_ITS_CTE_VALID_MASK		BIT_ULL(63)
 #define KVM_ITS_CTE_RDBASE_SHIFT	16
 #define KVM_ITS_CTE_ICID_MASK		GENMASK_ULL(15, 0)
+#define KVM_ITS_ITE_NEXT_SHIFT		48
+#define KVM_ITS_ITE_PINTID_SHIFT	16
+#define KVM_ITS_ITE_PINTID_MASK		GENMASK_ULL(47, 16)
+#define KVM_ITS_ITE_ICID_MASK		GENMASK_ULL(15, 0)
 #define KVM_ITS_DTE_VALID_SHIFT		63
 #define KVM_ITS_DTE_VALID_MASK		BIT_ULL(63)
 #define KVM_ITS_DTE_NEXT_SHIFT		49
-- 
2.5.5

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

* [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

Implement routines to save and restore device ITT and their
interrupt table entries (ITE).

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- added Christoffer's R-b

v5 -> v6:
- accomodate vgic_its_alloc_ite change of proto
- check LPI ID on restore, check eventid offset
- initializations on separate line
- coming after device save/restore
- add_lpi does config and pending bit sync

v4 -> v5:
- ITE are now sorted by eventid on the flush
- rename *flush* into *save*
- use macros for shits and masks
- pass ite_esz to vgic_its_save_ite

v3 -> v4:
- lookup_table and compute_next_eventid_offset become static in this
  patch
- remove static along with vgic_its_flush/restore_itt to avoid
  compilation warnings
- next field only computed with a shift (mask removed)
- handle the case where the last element has not been found

v2 -> v3:
- add return 0 in vgic_its_restore_ite (was in subsequent patch)

v2: creation
---
 virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
 virt/kvm/arm/vgic/vgic.h     |   4 ++
 2 files changed, 117 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 3dea626..adb3d9e 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
 	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
 }
 
-u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
+static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
 {
 	struct its_ite *next;
 	u32 next_offset;
@@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
 	return ret;
 }
 
+/**
+ * vgic_its_save_ite - Save an interrupt translation entry at @gpa
+ */
+static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
+			      struct its_ite *ite, gpa_t gpa, int ite_esz)
+{
+	struct kvm *kvm = its->dev->kvm;
+	u32 next_offset;
+	u64 val;
+
+	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
+	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
+	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
+		ite->collection->collection_id;
+	val = cpu_to_le64(val);
+	return kvm_write_guest(kvm, gpa, &val, ite_esz);
+}
+
+/**
+ * vgic_its_restore_ite - restore an interrupt translation entry
+ * @event_id: id used for indexing
+ * @ptr: pointer to the ITE entry
+ * @opaque: pointer to the its_device
+ */
+static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
+				void *ptr, void *opaque)
+{
+	struct its_device *dev = (struct its_device *)opaque;
+	struct its_collection *collection;
+	struct kvm *kvm = its->dev->kvm;
+	struct kvm_vcpu *vcpu = NULL;
+	u64 val;
+	u64 *p = (u64 *)ptr;
+	struct vgic_irq *irq;
+	u32 coll_id, lpi_id;
+	struct its_ite *ite;
+	u32 offset;
+
+	val = *p;
+
+	val = le64_to_cpu(val);
+
+	coll_id = val & KVM_ITS_ITE_ICID_MASK;
+	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
+
+	if (!lpi_id)
+		return 1; /* invalid entry, no choice but to scan next entry */
+
+	if (lpi_id < VGIC_MIN_LPI)
+		return -EINVAL;
+
+	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
+	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
+		return -EINVAL;
+
+	collection = find_collection(its, coll_id);
+	if (!collection)
+		return -EINVAL;
+
+	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
+	if (IS_ERR(ite))
+		return PTR_ERR(ite);
+
+	if (its_is_collection_mapped(collection))
+		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
+
+	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
+	if (IS_ERR(irq))
+		return PTR_ERR(irq);
+	ite->irq = irq;
+
+	return offset;
+}
+
+static int vgic_its_ite_cmp(void *priv, struct list_head *a,
+			    struct list_head *b)
+{
+	struct its_ite *itea = container_of(a, struct its_ite, ite_list);
+	struct its_ite *iteb = container_of(b, struct its_ite, ite_list);
+
+	if (itea->event_id < iteb->event_id)
+		return -1;
+	else
+		return 1;
+}
+
 static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	gpa_t base = device->itt_addr;
+	struct its_ite *ite;
+	int ret;
+	int ite_esz = abi->ite_esz;
+
+	list_sort(NULL, &device->itt_head, vgic_its_ite_cmp);
+
+	list_for_each_entry(ite, &device->itt_head, ite_list) {
+		gpa_t gpa = base + ite->event_id * ite_esz;
+
+		ret = vgic_its_save_ite(its, device, ite, gpa, ite_esz);
+		if (ret)
+			return ret;
+	}
+	return 0;
 }
 
 static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
 {
-	return -ENXIO;
+	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+	gpa_t base = dev->itt_addr;
+	int ret;
+	int ite_esz = abi->ite_esz;
+	size_t max_size = BIT_ULL(dev->num_eventid_bits) * ite_esz;
+
+	ret = scan_its_table(its, base, max_size, ite_esz, 0,
+			     vgic_its_restore_ite, dev);
+
+	return ret;
 }
 
 /**
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index e896114..92a8ca0 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -81,6 +81,10 @@
 #define KVM_ITS_CTE_VALID_MASK		BIT_ULL(63)
 #define KVM_ITS_CTE_RDBASE_SHIFT	16
 #define KVM_ITS_CTE_ICID_MASK		GENMASK_ULL(15, 0)
+#define KVM_ITS_ITE_NEXT_SHIFT		48
+#define KVM_ITS_ITE_PINTID_SHIFT	16
+#define KVM_ITS_ITE_PINTID_MASK		GENMASK_ULL(47, 16)
+#define KVM_ITS_ITE_ICID_MASK		GENMASK_ULL(15, 0)
 #define KVM_ITS_DTE_VALID_SHIFT		63
 #define KVM_ITS_DTE_VALID_MASK		BIT_ULL(63)
 #define KVM_ITS_DTE_NEXT_SHIFT		49
-- 
2.5.5

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

* [PATCH v7 23/24] KVM: arm64: vgic-its: Fix pending table sync
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

In its_sync_lpi_pending_table() we currently ignore the
target_vcpu of the LPIs. We sync the pending bit found in
the vcpu pending table even if the LPI is not targeting it.

Also in vgic_its_cmd_handle_invall() we are supposed to
read the config table data for the LPIs associated to the
collection ID. At the moment we refresh all LPI config
information.

This patch passes a vpcu to vgic_copy_lpi_list() so that
this latter returns a snapshot of the LPIs targeting this
CPU and only those.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---

v6 -> v7:
- added Christoffer's R-b
---
 virt/kvm/arm/vgic/vgic-its.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index adb3d9e..9f7105c 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -301,13 +301,13 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
 }
 
 /*
- * Create a snapshot of the current LPI list, so that we can enumerate all
- * LPIs without holding any lock.
- * Returns the array length and puts the kmalloc'ed array into intid_ptr.
+ * Create a snapshot of the current LPIs targeting @vcpu, so that we can
+ * enumerate those LPIs without holding any lock.
+ * Returns their number and puts the kmalloc'ed array into intid_ptr.
  */
-static int vgic_copy_lpi_list(struct kvm *kvm, u32 **intid_ptr)
+static int vgic_copy_lpi_list(struct kvm_vcpu *vcpu, u32 **intid_ptr)
 {
-	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct vgic_irq *irq;
 	u32 *intids;
 	int irq_count = dist->lpi_list_count, i = 0;
@@ -326,14 +326,14 @@ static int vgic_copy_lpi_list(struct kvm *kvm, u32 **intid_ptr)
 	spin_lock(&dist->lpi_list_lock);
 	list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
 		/* We don't need to "get" the IRQ, as we hold the list lock. */
-		intids[i] = irq->intid;
-		if (++i == irq_count)
-			break;
+		if (irq->target_vcpu != vcpu)
+			continue;
+		intids[i++] = irq->intid;
 	}
 	spin_unlock(&dist->lpi_list_lock);
 
 	*intid_ptr = intids;
-	return irq_count;
+	return i;
 }
 
 /*
@@ -382,7 +382,7 @@ static u32 max_lpis_propbaser(u64 propbaser)
 }
 
 /*
- * Scan the whole LPI pending table and sync the pending bit in there
+ * Sync the pending table pending bit of LPIs targeting @vcpu
  * with our own data structures. This relies on the LPI being
  * mapped before.
  */
@@ -395,7 +395,7 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
 	u32 *intids;
 	int nr_irqs, i;
 
-	nr_irqs = vgic_copy_lpi_list(vcpu->kvm, &intids);
+	nr_irqs = vgic_copy_lpi_list(vcpu, &intids);
 	if (nr_irqs < 0)
 		return nr_irqs;
 
@@ -1081,7 +1081,7 @@ static int vgic_its_cmd_handle_invall(struct kvm *kvm, struct vgic_its *its,
 
 	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
 
-	irq_count = vgic_copy_lpi_list(kvm, &intids);
+	irq_count = vgic_copy_lpi_list(vcpu, &intids);
 	if (irq_count < 0)
 		return irq_count;
 
-- 
2.5.5

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

* [PATCH v7 23/24] KVM: arm64: vgic-its: Fix pending table sync
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

In its_sync_lpi_pending_table() we currently ignore the
target_vcpu of the LPIs. We sync the pending bit found in
the vcpu pending table even if the LPI is not targeting it.

Also in vgic_its_cmd_handle_invall() we are supposed to
read the config table data for the LPIs associated to the
collection ID. At the moment we refresh all LPI config
information.

This patch passes a vpcu to vgic_copy_lpi_list() so that
this latter returns a snapshot of the LPIs targeting this
CPU and only those.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---

v6 -> v7:
- added Christoffer's R-b
---
 virt/kvm/arm/vgic/vgic-its.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index adb3d9e..9f7105c 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -301,13 +301,13 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
 }
 
 /*
- * Create a snapshot of the current LPI list, so that we can enumerate all
- * LPIs without holding any lock.
- * Returns the array length and puts the kmalloc'ed array into intid_ptr.
+ * Create a snapshot of the current LPIs targeting @vcpu, so that we can
+ * enumerate those LPIs without holding any lock.
+ * Returns their number and puts the kmalloc'ed array into intid_ptr.
  */
-static int vgic_copy_lpi_list(struct kvm *kvm, u32 **intid_ptr)
+static int vgic_copy_lpi_list(struct kvm_vcpu *vcpu, u32 **intid_ptr)
 {
-	struct vgic_dist *dist = &kvm->arch.vgic;
+	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
 	struct vgic_irq *irq;
 	u32 *intids;
 	int irq_count = dist->lpi_list_count, i = 0;
@@ -326,14 +326,14 @@ static int vgic_copy_lpi_list(struct kvm *kvm, u32 **intid_ptr)
 	spin_lock(&dist->lpi_list_lock);
 	list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
 		/* We don't need to "get" the IRQ, as we hold the list lock. */
-		intids[i] = irq->intid;
-		if (++i == irq_count)
-			break;
+		if (irq->target_vcpu != vcpu)
+			continue;
+		intids[i++] = irq->intid;
 	}
 	spin_unlock(&dist->lpi_list_lock);
 
 	*intid_ptr = intids;
-	return irq_count;
+	return i;
 }
 
 /*
@@ -382,7 +382,7 @@ static u32 max_lpis_propbaser(u64 propbaser)
 }
 
 /*
- * Scan the whole LPI pending table and sync the pending bit in there
+ * Sync the pending table pending bit of LPIs targeting @vcpu
  * with our own data structures. This relies on the LPI being
  * mapped before.
  */
@@ -395,7 +395,7 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
 	u32 *intids;
 	int nr_irqs, i;
 
-	nr_irqs = vgic_copy_lpi_list(vcpu->kvm, &intids);
+	nr_irqs = vgic_copy_lpi_list(vcpu, &intids);
 	if (nr_irqs < 0)
 		return nr_irqs;
 
@@ -1081,7 +1081,7 @@ static int vgic_its_cmd_handle_invall(struct kvm *kvm, struct vgic_its *its,
 
 	vcpu = kvm_get_vcpu(kvm, collection->target_addr);
 
-	irq_count = vgic_copy_lpi_list(kvm, &intids);
+	irq_count = vgic_copy_lpi_list(vcpu, &intids);
 	if (irq_count < 0)
 		return irq_count;
 
-- 
2.5.5

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

* [PATCH v7 24/24] KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
  2017-05-06 15:24 ` Eric Auger
@ 2017-05-06 15:24   ` Eric Auger
  -1 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, marc.zyngier, christoffer.dall,
	andre.przywara, vijayak, Vijaya.Kumar, peter.maydell,
	linux-arm-kernel, kvmarm, kvm
  Cc: Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela, bjsprakash.linux

This patch adds a new attribute to GICV3 KVM device
KVM_DEV_ARM_VGIC_GRP_CTRL group. This allows userspace to
flush all GICR pending tables into guest RAM.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- remove GICR_PENDBASER_ADDRESS
- added Christoffer's R-b

v5 -> v6:
- fix stored
- GICR_PEND/PROPBASER_ADDRESS were already introduced

v4 -> v5:
- move pending table save code/ctrl into VGICv3 instead of ITS
- remove useless gpa_t cast
- use the same optimization as in its_sync_lpi_pending_table

v3 -> v4:
- remove the wrong comment about locking
- pass kvm struct instead of its handle
- add comment about restore method
- remove GITR_PENDABASER.PTZ check
- continue if target_vcpu == NULL
- new locking strategy

v1 -> v2:
- do not care about the 1st KB which should be zeroed according to
  the spec.
---
 arch/arm/include/uapi/asm/kvm.h     |  1 +
 arch/arm64/include/uapi/asm/kvm.h   |  1 +
 virt/kvm/arm/vgic/vgic-kvm-device.c | 20 +++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         | 51 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |  1 +
 5 files changed, 74 insertions(+)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 8e6563c..78fe803 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -202,6 +202,7 @@ struct kvm_arch_memory_slot {
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
 #define   KVM_DEV_ARM_ITS_SAVE_TABLES		1
 #define   KVM_DEV_ARM_ITS_RESTORE_TABLES	2
+#define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 1e35115..8a3758a 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -222,6 +222,7 @@ struct kvm_arch_memory_slot {
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
 #define   KVM_DEV_ARM_ITS_SAVE_TABLES           1
 #define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
+#define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 859bfa8..d48743c 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -580,6 +580,24 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 		reg = tmp32;
 		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
 	}
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		int ret;
+
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
+			mutex_lock(&dev->kvm->lock);
+
+			if (!lock_all_vcpus(dev->kvm)) {
+				mutex_unlock(&dev->kvm->lock);
+				return -EBUSY;
+			}
+			ret = vgic_v3_save_pending_tables(dev->kvm);
+			unlock_all_vcpus(dev->kvm);
+			mutex_unlock(&dev->kvm->lock);
+			return ret;
+		}
+		break;
+	}
 	}
 	return -ENXIO;
 }
@@ -658,6 +676,8 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			return 0;
+		case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
+			return 0;
 		}
 	}
 	return -ENXIO;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 0d753ae..6ff6510 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -296,6 +296,57 @@ int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
 	return 0;
 }
 
+/**
+ * vgic_its_save_pending_tables - Save the pending tables into guest RAM
+ * kvm lock and all vcpu lock must be held
+ */
+int vgic_v3_save_pending_tables(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int last_byte_offset = -1;
+	struct vgic_irq *irq;
+	int ret;
+
+	list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
+		int byte_offset, bit_nr;
+		struct kvm_vcpu *vcpu;
+		gpa_t pendbase, ptr;
+		bool stored;
+		u8 val;
+
+		vcpu = irq->target_vcpu;
+		if (!vcpu)
+			continue;
+
+		pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
+
+		byte_offset = irq->intid / BITS_PER_BYTE;
+		bit_nr = irq->intid % BITS_PER_BYTE;
+		ptr = pendbase + byte_offset;
+
+		if (byte_offset != last_byte_offset) {
+			ret = kvm_read_guest(kvm, ptr, &val, 1);
+			if (ret)
+				return ret;
+			last_byte_offset = byte_offset;
+		}
+
+		stored = val & (1U << bit_nr);
+		if (stored == irq->pending_latch)
+			continue;
+
+		if (irq->pending_latch)
+			val |= 1 << bit_nr;
+		else
+			val &= ~(1 << bit_nr);
+
+		ret = kvm_write_guest(kvm, ptr, &val, 1);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 /* check for overlapping regions and for regions crossing the end of memory */
 static bool vgic_v3_check_base(struct kvm *kvm)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 92a8ca0..8de59a4 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -181,6 +181,7 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
+int vgic_v3_save_pending_tables(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 
 int vgic_register_its_iodevs(struct kvm *kvm);
-- 
2.5.5

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

* [PATCH v7 24/24] KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
@ 2017-05-06 15:24   ` Eric Auger
  0 siblings, 0 replies; 110+ messages in thread
From: Eric Auger @ 2017-05-06 15:24 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a new attribute to GICV3 KVM device
KVM_DEV_ARM_VGIC_GRP_CTRL group. This allows userspace to
flush all GICR pending tables into guest RAM.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>

---
v6 -> v7:
- remove GICR_PENDBASER_ADDRESS
- added Christoffer's R-b

v5 -> v6:
- fix stored
- GICR_PEND/PROPBASER_ADDRESS were already introduced

v4 -> v5:
- move pending table save code/ctrl into VGICv3 instead of ITS
- remove useless gpa_t cast
- use the same optimization as in its_sync_lpi_pending_table

v3 -> v4:
- remove the wrong comment about locking
- pass kvm struct instead of its handle
- add comment about restore method
- remove GITR_PENDABASER.PTZ check
- continue if target_vcpu == NULL
- new locking strategy

v1 -> v2:
- do not care about the 1st KB which should be zeroed according to
  the spec.
---
 arch/arm/include/uapi/asm/kvm.h     |  1 +
 arch/arm64/include/uapi/asm/kvm.h   |  1 +
 virt/kvm/arm/vgic/vgic-kvm-device.c | 20 +++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c         | 51 +++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h            |  1 +
 5 files changed, 74 insertions(+)

diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 8e6563c..78fe803 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -202,6 +202,7 @@ struct kvm_arch_memory_slot {
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
 #define   KVM_DEV_ARM_ITS_SAVE_TABLES		1
 #define   KVM_DEV_ARM_ITS_RESTORE_TABLES	2
+#define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 1e35115..8a3758a 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -222,6 +222,7 @@ struct kvm_arch_memory_slot {
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
 #define   KVM_DEV_ARM_ITS_SAVE_TABLES           1
 #define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
+#define   KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES	3
 
 /* Device Control API on vcpu fd */
 #define KVM_ARM_VCPU_PMU_V3_CTRL	0
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 859bfa8..d48743c 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -580,6 +580,24 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 		reg = tmp32;
 		return vgic_v3_attr_regs_access(dev, attr, &reg, true);
 	}
+	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
+		int ret;
+
+		switch (attr->attr) {
+		case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
+			mutex_lock(&dev->kvm->lock);
+
+			if (!lock_all_vcpus(dev->kvm)) {
+				mutex_unlock(&dev->kvm->lock);
+				return -EBUSY;
+			}
+			ret = vgic_v3_save_pending_tables(dev->kvm);
+			unlock_all_vcpus(dev->kvm);
+			mutex_unlock(&dev->kvm->lock);
+			return ret;
+		}
+		break;
+	}
 	}
 	return -ENXIO;
 }
@@ -658,6 +676,8 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 		switch (attr->attr) {
 		case KVM_DEV_ARM_VGIC_CTRL_INIT:
 			return 0;
+		case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
+			return 0;
 		}
 	}
 	return -ENXIO;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 0d753ae..6ff6510 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -296,6 +296,57 @@ int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
 	return 0;
 }
 
+/**
+ * vgic_its_save_pending_tables - Save the pending tables into guest RAM
+ * kvm lock and all vcpu lock must be held
+ */
+int vgic_v3_save_pending_tables(struct kvm *kvm)
+{
+	struct vgic_dist *dist = &kvm->arch.vgic;
+	int last_byte_offset = -1;
+	struct vgic_irq *irq;
+	int ret;
+
+	list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
+		int byte_offset, bit_nr;
+		struct kvm_vcpu *vcpu;
+		gpa_t pendbase, ptr;
+		bool stored;
+		u8 val;
+
+		vcpu = irq->target_vcpu;
+		if (!vcpu)
+			continue;
+
+		pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
+
+		byte_offset = irq->intid / BITS_PER_BYTE;
+		bit_nr = irq->intid % BITS_PER_BYTE;
+		ptr = pendbase + byte_offset;
+
+		if (byte_offset != last_byte_offset) {
+			ret = kvm_read_guest(kvm, ptr, &val, 1);
+			if (ret)
+				return ret;
+			last_byte_offset = byte_offset;
+		}
+
+		stored = val & (1U << bit_nr);
+		if (stored == irq->pending_latch)
+			continue;
+
+		if (irq->pending_latch)
+			val |= 1 << bit_nr;
+		else
+			val &= ~(1 << bit_nr);
+
+		ret = kvm_write_guest(kvm, ptr, &val, 1);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
 /* check for overlapping regions and for regions crossing the end of memory */
 static bool vgic_v3_check_base(struct kvm *kvm)
 {
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 92a8ca0..8de59a4 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -181,6 +181,7 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu);
 int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
+int vgic_v3_save_pending_tables(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 
 int vgic_register_its_iodevs(struct kvm *kvm);
-- 
2.5.5

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

* Re: [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 11:54     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 11:54 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add description for how to access ITS registers and how to save/restore
> ITS tables into/from memory.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
> ---
> v6 -> v7:
> - rephrase ordering sequence + few cosmetic changes
>
> v5 -> v6:
> - add restoration ordering
> - 256B -> 256 Byte aligned
> - DTE Size is number of bits for the EVENTID
> - s/GITS_READR/GITS_CREADR
>
> v4 -> v5:
> - take into account Christoffer's comments
> - pending table save on GICV3 side now
>
> v3 -> v4:
> - take into account Peter's comments:
>   - typos
>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
>   - add a validity bit in DTE
>   - document all fields in CTE and ITE
>   - document ABI revision
> - take into account Andre's comments:
>   - document restrictions about GITS_CREADR writing and GITS_IIDR
>   - document -EBUSY error if one or more VCPUS are runnning
>   - document 64b registers only can be accessed with 64b access
> - itt_addr field matches bits [51:8] of the itt_addr
>
> v1 -> v2:
> - DTE and ITE now are 8 bytes
> - DTE and ITE now indexed by deviceid/eventid
> - use ITE name instead of ITTE
> - mentions ITT_addr matches bits [51:8] of the actual address
> - mentions LE layout
> ---
>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
>  1 file changed, 120 insertions(+)
>
> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> index 6081a5b..ba132e9 100644
> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
[...]

> + ITS Table ABI REV0:
> + -------------------
> +
> + Revision 0 of the ABI only supports physical LPIs.

Nit: these are no more physical than any other interrupt that KVM deals
with. If you're hinting at the lack of GICv4 support, it wouldn't
necessarily invalidate this ABI. It is actually even likely that the ABI
could stay the same (until we start supporting GICv4 in a nested
configuration).

> +
> + The device table and ITT are indexed by the deviceid and eventid,
> + respectively. The collection table is not indexed by collectionid:
> + CTEs are written in the table in the order of collection creation. All

Is this order really relevant? Can we relax it? Would something break if
collections were in a random order?

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
@ 2017-05-07 11:54     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 11:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add description for how to access ITS registers and how to save/restore
> ITS tables into/from memory.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
> ---
> v6 -> v7:
> - rephrase ordering sequence + few cosmetic changes
>
> v5 -> v6:
> - add restoration ordering
> - 256B -> 256 Byte aligned
> - DTE Size is number of bits for the EVENTID
> - s/GITS_READR/GITS_CREADR
>
> v4 -> v5:
> - take into account Christoffer's comments
> - pending table save on GICV3 side now
>
> v3 -> v4:
> - take into account Peter's comments:
>   - typos
>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
>   - add a validity bit in DTE
>   - document all fields in CTE and ITE
>   - document ABI revision
> - take into account Andre's comments:
>   - document restrictions about GITS_CREADR writing and GITS_IIDR
>   - document -EBUSY error if one or more VCPUS are runnning
>   - document 64b registers only can be accessed with 64b access
> - itt_addr field matches bits [51:8] of the itt_addr
>
> v1 -> v2:
> - DTE and ITE now are 8 bytes
> - DTE and ITE now indexed by deviceid/eventid
> - use ITE name instead of ITTE
> - mentions ITT_addr matches bits [51:8] of the actual address
> - mentions LE layout
> ---
>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
>  1 file changed, 120 insertions(+)
>
> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> index 6081a5b..ba132e9 100644
> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
[...]

> + ITS Table ABI REV0:
> + -------------------
> +
> + Revision 0 of the ABI only supports physical LPIs.

Nit: these are no more physical than any other interrupt that KVM deals
with. If you're hinting at the lack of GICv4 support, it wouldn't
necessarily invalidate this ABI. It is actually even likely that the ABI
could stay the same (until we start supporting GICv4 in a nested
configuration).

> +
> + The device table and ITT are indexed by the deviceid and eventid,
> + respectively. The collection table is not indexed by collectionid:
> + CTEs are written in the table in the order of collection creation. All

Is this order really relevant? Can we relax it? Would something break if
collections were in a random order?

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 02/24] KVM: arm/arm64: Add GICV3 pending table save API documentation
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 11:56     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 11:56 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:21 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add description for how to save GICV3 LPI pending bit into
> guest RAM pending tables.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Acked-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 02/24] KVM: arm/arm64: Add GICV3 pending table save API documentation
@ 2017-05-07 11:56     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 11:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:21 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add description for how to save GICV3 LPI pending bit into
> guest RAM pending tables.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Acked-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 07/24] KVM: arm64: vgic-its: Implement vgic_its_has_attr_regs and attr_regs_access
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 11:57     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 11:57 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:26 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> This patch implements vgic_its_has_attr_regs and vgic_its_attr_regs_access
> upon the MMIO framework. VGIC ITS KVM device KVM_DEV_ARM_VGIC_GRP_ITS_REGS
> group becomes functional.
>
> At least GITS_CREADR and GITS_IIDR require to differentiate a guest write
> action from a user access. As such let's introduce a new uaccess_its_write
> vgic_register_region callback.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 07/24] KVM: arm64: vgic-its: Implement vgic_its_has_attr_regs and attr_regs_access
@ 2017-05-07 11:57     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 11:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:26 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> This patch implements vgic_its_has_attr_regs and vgic_its_attr_regs_access
> upon the MMIO framework. VGIC ITS KVM device KVM_DEV_ARM_VGIC_GRP_ITS_REGS
> group becomes functional.
>
> At least GITS_CREADR and GITS_IIDR require to differentiate a guest write
> action from a user access. As such let's introduce a new uaccess_its_write
> vgic_register_region callback.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 13/24] KVM: arm64: vgic-its: Check the device id matches TYPER DEVBITS range
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 12:01     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 12:01 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:32 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> On MAPD we currently check the device id can be stored in the device table.
> Let's first check it can be encoded within the range defined by TYPER
> DEVBITS.
>
> Also check the collection ID belongs to the 16 bit range as GITS_TYPER
> CIL field equals to 0.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 13/24] KVM: arm64: vgic-its: Check the device id matches TYPER DEVBITS range
@ 2017-05-07 12:01     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 12:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:32 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> On MAPD we currently check the device id can be stored in the device table.
> Let's first check it can be encoded within the range defined by TYPER
> DEVBITS.
>
> Also check the collection ID belongs to the 16 bit range as GITS_TYPER
> CIL field equals to 0.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 14/24] KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 12:13     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 12:13 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:33 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> this new helper synchronizes the irq pending_latch
> with the LPI pending bit status found in rdist pending table.
> As the status is consumed, we reset the bit in pending table.
>
> As we need the PENDBASER_ADDRESS() in vgic-v3, let's move its
> definition in the irqchip header. We restore the full length
> of the field, ie [51:16]. Same for PROPBASER_ADDRESS with full
> field length of [51:12].
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 14/24] KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
@ 2017-05-07 12:13     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 12:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:33 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> this new helper synchronizes the irq pending_latch
> with the LPI pending bit status found in rdist pending table.
> As the status is consumed, we reset the bit in pending table.
>
> As we need the PENDBASER_ADDRESS() in vgic-v3, let's move its
> definition in the irqchip header. We restore the full length
> of the field, ie [51:16]. Same for PROPBASER_ADDRESS with full
> field length of [51:12].
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 15/24] KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 12:16     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 12:16 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:34 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> When creating the lpi we now ask the redistributor what is the state
> of the LPI (priority, enabled, pending).
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 15/24] KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
@ 2017-05-07 12:16     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:34 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> When creating the lpi we now ask the redistributor what is the state
> of the LPI (priority, enabled, pending).
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:00     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:00 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>   structures.
>
> We hold the vcpus lock during the save and restore to make
> sure no vcpu is running.
>
> At this stage the functionality is not yet implemented. Only
> the skeleton is put in place.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
> ---
> v6 -> v7:
> - also hold the its_lock on save and restore
>
> v5 -> v6:
> - remove the pending table sync from the ITS table restore
>
> v4 -> v5:
> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
> - rename *flush* into *save*
> - call its_sync_lpi_pending_table at the end of restore
> - use abi framework
>
> v3 -> v4:
> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
> - take the kvm lock and vcpu locks
> - ABI revision check
> - check attr->attr is null
>
> v1 -> v2:
> - remove useless kvm parameter
> ---
>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>  3 files changed, 109 insertions(+), 6 deletions(-)
>

[...]

> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>   */
>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>  {
> -	return -ENXIO;
> +	struct kvm *kvm = its->dev->kvm;
> +	int ret;
> +
> +	mutex_lock(&kvm->lock);
> +	mutex_lock(&its->its_lock);
> +
> +	if (!lock_all_vcpus(kvm)) {
> +		mutex_unlock(&its->its_lock);
> +		mutex_unlock(&kvm->lock);
> +		return -EBUSY;
> +	}
> +
> +	ret = vgic_its_restore_collection_table(its);
> +	if (ret)
> +		goto out;
> +
> +	ret = vgic_its_restore_device_tables(its);
> +
> +out:
> +	unlock_all_vcpus(kvm);
> +	mutex_unlock(&its->its_lock);
> +	mutex_unlock(&kvm->lock);
> +
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * On restore path, MSI injections can happen before the
> +	 * first VCPU run so let's complete the GIC init here.
> +	 */
> +	return kvm_vgic_map_resources(its->dev->kvm);

This one is still a rather sore spot, but I've lost track of what we can
do about it. Until now, this would only happen on first run. But it
looks like QEMU and KVM have different views of what "runable" is.

I'm not sure there is a good way to solve this, unfortunately. From a
device PoV, everything is ready and the fact that nothing is clocking
the CPUs is very much irrelevant. I'm almost tempted to say that the
map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
that we're missing a synchronization point with userspace that would say
"system is entierely configured", triggering the iodev registration.

Oh well. At that point, and short of having something better to offer:

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
@ 2017-05-07 13:00     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>   structures.
>
> We hold the vcpus lock during the save and restore to make
> sure no vcpu is running.
>
> At this stage the functionality is not yet implemented. Only
> the skeleton is put in place.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
> ---
> v6 -> v7:
> - also hold the its_lock on save and restore
>
> v5 -> v6:
> - remove the pending table sync from the ITS table restore
>
> v4 -> v5:
> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
> - rename *flush* into *save*
> - call its_sync_lpi_pending_table at the end of restore
> - use abi framework
>
> v3 -> v4:
> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
> - take the kvm lock and vcpu locks
> - ABI revision check
> - check attr->attr is null
>
> v1 -> v2:
> - remove useless kvm parameter
> ---
>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>  3 files changed, 109 insertions(+), 6 deletions(-)
>

[...]

> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>   */
>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>  {
> -	return -ENXIO;
> +	struct kvm *kvm = its->dev->kvm;
> +	int ret;
> +
> +	mutex_lock(&kvm->lock);
> +	mutex_lock(&its->its_lock);
> +
> +	if (!lock_all_vcpus(kvm)) {
> +		mutex_unlock(&its->its_lock);
> +		mutex_unlock(&kvm->lock);
> +		return -EBUSY;
> +	}
> +
> +	ret = vgic_its_restore_collection_table(its);
> +	if (ret)
> +		goto out;
> +
> +	ret = vgic_its_restore_device_tables(its);
> +
> +out:
> +	unlock_all_vcpus(kvm);
> +	mutex_unlock(&its->its_lock);
> +	mutex_unlock(&kvm->lock);
> +
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * On restore path, MSI injections can happen before the
> +	 * first VCPU run so let's complete the GIC init here.
> +	 */
> +	return kvm_vgic_map_resources(its->dev->kvm);

This one is still a rather sore spot, but I've lost track of what we can
do about it. Until now, this would only happen on first run. But it
looks like QEMU and KVM have different views of what "runable" is.

I'm not sure there is a good way to solve this, unfortunately. From a
device PoV, everything is ready and the fact that nothing is clocking
the CPUs is very much irrelevant. I'm almost tempted to say that the
map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
that we're missing a synchronization point with userspace that would say
"system is entierely configured", triggering the iodev registration.

Oh well. At that point, and short of having something better to offer:

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 17/24] KVM: arm64: vgic-its: vgic_its_alloc_ite/device
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:02     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:02 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:36 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add two new helpers to allocate an its ite and an its device.
> This will avoid duplication on restore path.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 17/24] KVM: arm64: vgic-its: vgic_its_alloc_ite/device
@ 2017-05-07 13:02     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:36 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add two new helpers to allocate an its ite and an its device.
> This will avoid duplication on restore path.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 18/24] KVM: arm64: vgic-its: Add infrastructure for table lookup
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:05     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:05 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:37 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add a generic scan_its_table() helper whose role consists in
> scanning a contiguous table located in guest RAM and applying
> a callback on each entry. Entries can be handled as linked lists
> since the callback may return an id offset to the next entry and
> also indicate whether the entry is the last one.
>
> Helper functions also are added to compute the device/event ID
> offset to the next DTE/ITE.
>
> compute_next_devid_offset, compute_next_eventid_offset and
> scan_table will become static in subsequent patches
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 18/24] KVM: arm64: vgic-its: Add infrastructure for table lookup
@ 2017-05-07 13:05     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:37 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Add a generic scan_its_table() helper whose role consists in
> scanning a contiguous table located in guest RAM and applying
> a callback on each entry. Entries can be handled as linked lists
> since the callback may return an id offset to the next entry and
> also indicate whether the entry is the last one.
>
> Helper functions also are added to compute the device/event ID
> offset to the next DTE/ITE.
>
> compute_next_devid_offset, compute_next_eventid_offset and
> scan_table will become static in subsequent patches
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 19/24] KVM: arm64: vgic-its: Collection table save/restore
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:12     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:12 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:38 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> The save path copies the collection entries into guest RAM
> at the GPA specified in the BASER register. This obviously
> requires the BASER to be set. The last written element is a
> dummy collection table entry.
>
> We do not index by collection ID as the collection entry
> can fit into 8 bytes while containing the collection ID.
>
> On restore path we re-allocate the collection objects.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 19/24] KVM: arm64: vgic-its: Collection table save/restore
@ 2017-05-07 13:12     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:38 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> The save path copies the collection entries into guest RAM
> at the GPA specified in the BASER register. This obviously
> requires the BASER to be set. The last written element is a
> dummy collection table entry.
>
> We do not index by collection ID as the collection entry
> can fit into 8 bytes while containing the collection ID.
>
> On restore path we re-allocate the collection objects.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 20/24] KVM: arm64: vgic-its: vgic_its_check_id returns the entry's GPA
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:14     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:14 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:39 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> As vgic_its_check_id() computes the device/collection entry's
> GPA, let's return it so that new callers can retrieve it easily.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Acked-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 20/24] KVM: arm64: vgic-its: vgic_its_check_id returns the entry's GPA
@ 2017-05-07 13:14     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:39 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> As vgic_its_check_id() computes the device/collection entry's
> GPA, let's return it so that new callers can retrieve it easily.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Acked-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:30     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:30 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:40 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> This patch saves the device table entries into guest RAM.
> Both flat table and 2 stage tables are supported. DeviceId
> indexing is used.
>
> For each device listed in the device table, we also save
> the translation table using the vgic_its_save/restore_itt
> routines. Those functions will be implemented in a subsequent
> patch.
>
> On restore, devices are re-allocated and their itt are
> re-built.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
> ---
> v5 -> v6:
> - accomodate vgic_its_alloc_device change of proto
> - define bit fields for L1 entries
> - s/handle_l1_entry/handle_l1_dte
> - s/ite_esz/dte_esz in handle_l1_dte
> - check BASER valid bit
> - s/nb_eventid_bits/num_eventid_bits
> - new convention for returned values
> - itt functions implemented in subsequent patch
>
> v4 -> v5:
> - sort the device list by deviceid on device table save
> - use defines for shifts and masks
> - use abi->dte_esz
> - clatify entry sizes for L1 and L2 tables
>
> v3 -> v4:
> - use the new proto for its_alloc_device
> - compute_next_devid_offset, vgic_its_flush/restore_itt
>   become static in this patch
> - change in the DTE entry format with the introduction of the
>   valid bit and next field width decrease; ittaddr encoded
>   on its full range
> - fix handle_l1_entry entry handling
> - correct vgic_its_table_restore error handling
>
> v2 -> v3:
> - fix itt_addr bitmask in vgic_its_restore_dte
> - addition of return 0 in vgic_its_restore_ite moved to
>   the ITE related patch
>
> v1 -> v2:
> - use 8 byte format for DTE and ITE
> - support 2 stage format
> - remove kvm parameter
> - ITT flush/restore moved in a separate patch
> - use deviceid indexing
> ---
>  virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.h     |  10 +++
>  2 files changed, 199 insertions(+), 5 deletions(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index 90afc83..3dea626 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -23,6 +23,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/list.h>
>  #include <linux/uaccess.h>
> +#include <linux/list_sort.h>
>  
>  #include <linux/irqchip/arm-gic-v3.h>
>  
> @@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
>  	return ret;
>  }
>  
> -u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
> +static u32 compute_next_devid_offset(struct list_head *h,
> +				     struct its_device *dev)
>  {
>  	struct its_device *next;
>  	u32 next_offset;
> @@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
>   * Return: < 0 on error, 0 if last element was identified, 1 otherwise
>   * (the last element may not be found on second level tables)
>   */
> -int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> -		   int start_id, entry_fn_t fn, void *opaque)
> +static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> +			  int start_id, entry_fn_t fn, void *opaque)
>  {
>  	void *entry = kzalloc(esz, GFP_KERNEL);
>  	struct kvm *kvm = its->dev->kvm;
> @@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>  	return ret;
>  }
>  
> +static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
> +{
> +	return -ENXIO;
> +}
> +
> +static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_save_dte - Save a device table entry at a given GPA
> + *
> + * @its: ITS handle
> + * @dev: ITS device
> + * @ptr: GPA
> + */
> +static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
> +			     gpa_t ptr, int dte_esz)
> +{
> +	struct kvm *kvm = its->dev->kvm;
> +	u64 val, itt_addr_field;
> +	u32 next_offset;
> +
> +	itt_addr_field = dev->itt_addr >> 8;
> +	next_offset = compute_next_devid_offset(&its->device_list, dev);
> +	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
> +	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
> +	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
> +		(dev->num_eventid_bits - 1));
> +	val = cpu_to_le64(val);
> +	return kvm_write_guest(kvm, ptr, &val, dte_esz);
> +}
> +
> +/**
> + * vgic_its_restore_dte - restore a device table entry
> + *
> + * @its: its handle
> + * @id: device id the DTE corresponds to
> + * @ptr: kernel VA where the 8 byte DTE is located
> + * @opaque: unused
> + *
> + * Return: < 0 on error, 0 if the dte is the last one, id offset to the
> + * next dte otherwise
> + */
> +static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
> +				void *ptr, void *opaque)
> +{
> +	struct its_device *dev;
> +	gpa_t itt_addr;
> +	u8 num_eventid_bits;
> +	u64 entry = *(u64 *)ptr;
> +	bool valid;
> +	u32 offset;
> +	int ret;
> +
> +	entry = le64_to_cpu(entry);
> +
> +	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
> +	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
> +	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
> +			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
> +
> +	if (!valid)
> +		return 1;
> +
> +	/* dte entry is valid */
> +	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
> +
> +	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
> +	if (IS_ERR(dev))
> +		return PTR_ERR(dev);
> +
> +	ret = vgic_its_restore_itt(its, dev);
> +	if (ret)
> +		return ret;

Shouldn't we free the device entry if the restore as failed?

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
@ 2017-05-07 13:30     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:40 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> This patch saves the device table entries into guest RAM.
> Both flat table and 2 stage tables are supported. DeviceId
> indexing is used.
>
> For each device listed in the device table, we also save
> the translation table using the vgic_its_save/restore_itt
> routines. Those functions will be implemented in a subsequent
> patch.
>
> On restore, devices are re-allocated and their itt are
> re-built.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
> ---
> v5 -> v6:
> - accomodate vgic_its_alloc_device change of proto
> - define bit fields for L1 entries
> - s/handle_l1_entry/handle_l1_dte
> - s/ite_esz/dte_esz in handle_l1_dte
> - check BASER valid bit
> - s/nb_eventid_bits/num_eventid_bits
> - new convention for returned values
> - itt functions implemented in subsequent patch
>
> v4 -> v5:
> - sort the device list by deviceid on device table save
> - use defines for shifts and masks
> - use abi->dte_esz
> - clatify entry sizes for L1 and L2 tables
>
> v3 -> v4:
> - use the new proto for its_alloc_device
> - compute_next_devid_offset, vgic_its_flush/restore_itt
>   become static in this patch
> - change in the DTE entry format with the introduction of the
>   valid bit and next field width decrease; ittaddr encoded
>   on its full range
> - fix handle_l1_entry entry handling
> - correct vgic_its_table_restore error handling
>
> v2 -> v3:
> - fix itt_addr bitmask in vgic_its_restore_dte
> - addition of return 0 in vgic_its_restore_ite moved to
>   the ITE related patch
>
> v1 -> v2:
> - use 8 byte format for DTE and ITE
> - support 2 stage format
> - remove kvm parameter
> - ITT flush/restore moved in a separate patch
> - use deviceid indexing
> ---
>  virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.h     |  10 +++
>  2 files changed, 199 insertions(+), 5 deletions(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index 90afc83..3dea626 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -23,6 +23,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/list.h>
>  #include <linux/uaccess.h>
> +#include <linux/list_sort.h>
>  
>  #include <linux/irqchip/arm-gic-v3.h>
>  
> @@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
>  	return ret;
>  }
>  
> -u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
> +static u32 compute_next_devid_offset(struct list_head *h,
> +				     struct its_device *dev)
>  {
>  	struct its_device *next;
>  	u32 next_offset;
> @@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
>   * Return: < 0 on error, 0 if last element was identified, 1 otherwise
>   * (the last element may not be found on second level tables)
>   */
> -int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> -		   int start_id, entry_fn_t fn, void *opaque)
> +static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> +			  int start_id, entry_fn_t fn, void *opaque)
>  {
>  	void *entry = kzalloc(esz, GFP_KERNEL);
>  	struct kvm *kvm = its->dev->kvm;
> @@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>  	return ret;
>  }
>  
> +static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
> +{
> +	return -ENXIO;
> +}
> +
> +static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_save_dte - Save a device table entry at a given GPA
> + *
> + * @its: ITS handle
> + * @dev: ITS device
> + * @ptr: GPA
> + */
> +static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
> +			     gpa_t ptr, int dte_esz)
> +{
> +	struct kvm *kvm = its->dev->kvm;
> +	u64 val, itt_addr_field;
> +	u32 next_offset;
> +
> +	itt_addr_field = dev->itt_addr >> 8;
> +	next_offset = compute_next_devid_offset(&its->device_list, dev);
> +	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
> +	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
> +	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
> +		(dev->num_eventid_bits - 1));
> +	val = cpu_to_le64(val);
> +	return kvm_write_guest(kvm, ptr, &val, dte_esz);
> +}
> +
> +/**
> + * vgic_its_restore_dte - restore a device table entry
> + *
> + * @its: its handle
> + * @id: device id the DTE corresponds to
> + * @ptr: kernel VA where the 8 byte DTE is located
> + * @opaque: unused
> + *
> + * Return: < 0 on error, 0 if the dte is the last one, id offset to the
> + * next dte otherwise
> + */
> +static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
> +				void *ptr, void *opaque)
> +{
> +	struct its_device *dev;
> +	gpa_t itt_addr;
> +	u8 num_eventid_bits;
> +	u64 entry = *(u64 *)ptr;
> +	bool valid;
> +	u32 offset;
> +	int ret;
> +
> +	entry = le64_to_cpu(entry);
> +
> +	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
> +	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
> +	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
> +			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
> +
> +	if (!valid)
> +		return 1;
> +
> +	/* dte entry is valid */
> +	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
> +
> +	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
> +	if (IS_ERR(dev))
> +		return PTR_ERR(dev);
> +
> +	ret = vgic_its_restore_itt(its, dev);
> +	if (ret)
> +		return ret;

Shouldn't we free the device entry if the restore as failed?

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:39     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:39 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:41 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Implement routines to save and restore device ITT and their
> interrupt table entries (ITE).
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>
>
> ---
> v6 -> v7:
> - added Christoffer's R-b
>
> v5 -> v6:
> - accomodate vgic_its_alloc_ite change of proto
> - check LPI ID on restore, check eventid offset
> - initializations on separate line
> - coming after device save/restore
> - add_lpi does config and pending bit sync
>
> v4 -> v5:
> - ITE are now sorted by eventid on the flush
> - rename *flush* into *save*
> - use macros for shits and masks
> - pass ite_esz to vgic_its_save_ite
>
> v3 -> v4:
> - lookup_table and compute_next_eventid_offset become static in this
>   patch
> - remove static along with vgic_its_flush/restore_itt to avoid
>   compilation warnings
> - next field only computed with a shift (mask removed)
> - handle the case where the last element has not been found
>
> v2 -> v3:
> - add return 0 in vgic_its_restore_ite (was in subsequent patch)
>
> v2: creation
> ---
>  virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.h     |   4 ++
>  2 files changed, 117 insertions(+), 3 deletions(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index 3dea626..adb3d9e 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
>  	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
>  }
>  
> -u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
> +static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
>  {
>  	struct its_ite *next;
>  	u32 next_offset;
> @@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>  	return ret;
>  }
>  
> +/**
> + * vgic_its_save_ite - Save an interrupt translation entry at @gpa
> + */
> +static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
> +			      struct its_ite *ite, gpa_t gpa, int ite_esz)
> +{
> +	struct kvm *kvm = its->dev->kvm;
> +	u32 next_offset;
> +	u64 val;
> +
> +	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
> +	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
> +	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
> +		ite->collection->collection_id;
> +	val = cpu_to_le64(val);
> +	return kvm_write_guest(kvm, gpa, &val, ite_esz);
> +}
> +
> +/**
> + * vgic_its_restore_ite - restore an interrupt translation entry
> + * @event_id: id used for indexing
> + * @ptr: pointer to the ITE entry
> + * @opaque: pointer to the its_device
> + */
> +static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
> +				void *ptr, void *opaque)
> +{
> +	struct its_device *dev = (struct its_device *)opaque;
> +	struct its_collection *collection;
> +	struct kvm *kvm = its->dev->kvm;
> +	struct kvm_vcpu *vcpu = NULL;
> +	u64 val;
> +	u64 *p = (u64 *)ptr;
> +	struct vgic_irq *irq;
> +	u32 coll_id, lpi_id;
> +	struct its_ite *ite;
> +	u32 offset;
> +
> +	val = *p;
> +
> +	val = le64_to_cpu(val);
> +
> +	coll_id = val & KVM_ITS_ITE_ICID_MASK;
> +	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
> +
> +	if (!lpi_id)
> +		return 1; /* invalid entry, no choice but to scan next entry */
> +
> +	if (lpi_id < VGIC_MIN_LPI)
> +		return -EINVAL;
> +
> +	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
> +	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
> +		return -EINVAL;
> +
> +	collection = find_collection(its, coll_id);
> +	if (!collection)
> +		return -EINVAL;
> +
> +	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
> +	if (IS_ERR(ite))
> +		return PTR_ERR(ite);
> +
> +	if (its_is_collection_mapped(collection))
> +		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
> +
> +	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
> +	if (IS_ERR(irq))
> +		return PTR_ERR(irq);

Same remark as the previous patch: the its_ite structure should be freed
on failure. Otherwise, I suspect we end0up leaking memory.

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
@ 2017-05-07 13:39     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:41 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> Implement routines to save and restore device ITT and their
> interrupt table entries (ITE).
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>
>
> ---
> v6 -> v7:
> - added Christoffer's R-b
>
> v5 -> v6:
> - accomodate vgic_its_alloc_ite change of proto
> - check LPI ID on restore, check eventid offset
> - initializations on separate line
> - coming after device save/restore
> - add_lpi does config and pending bit sync
>
> v4 -> v5:
> - ITE are now sorted by eventid on the flush
> - rename *flush* into *save*
> - use macros for shits and masks
> - pass ite_esz to vgic_its_save_ite
>
> v3 -> v4:
> - lookup_table and compute_next_eventid_offset become static in this
>   patch
> - remove static along with vgic_its_flush/restore_itt to avoid
>   compilation warnings
> - next field only computed with a shift (mask removed)
> - handle the case where the last element has not been found
>
> v2 -> v3:
> - add return 0 in vgic_its_restore_ite (was in subsequent patch)
>
> v2: creation
> ---
>  virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
>  virt/kvm/arm/vgic/vgic.h     |   4 ++
>  2 files changed, 117 insertions(+), 3 deletions(-)
>
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index 3dea626..adb3d9e 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
>  	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
>  }
>  
> -u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
> +static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
>  {
>  	struct its_ite *next;
>  	u32 next_offset;
> @@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>  	return ret;
>  }
>  
> +/**
> + * vgic_its_save_ite - Save an interrupt translation entry at @gpa
> + */
> +static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
> +			      struct its_ite *ite, gpa_t gpa, int ite_esz)
> +{
> +	struct kvm *kvm = its->dev->kvm;
> +	u32 next_offset;
> +	u64 val;
> +
> +	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
> +	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
> +	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
> +		ite->collection->collection_id;
> +	val = cpu_to_le64(val);
> +	return kvm_write_guest(kvm, gpa, &val, ite_esz);
> +}
> +
> +/**
> + * vgic_its_restore_ite - restore an interrupt translation entry
> + * @event_id: id used for indexing
> + * @ptr: pointer to the ITE entry
> + * @opaque: pointer to the its_device
> + */
> +static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
> +				void *ptr, void *opaque)
> +{
> +	struct its_device *dev = (struct its_device *)opaque;
> +	struct its_collection *collection;
> +	struct kvm *kvm = its->dev->kvm;
> +	struct kvm_vcpu *vcpu = NULL;
> +	u64 val;
> +	u64 *p = (u64 *)ptr;
> +	struct vgic_irq *irq;
> +	u32 coll_id, lpi_id;
> +	struct its_ite *ite;
> +	u32 offset;
> +
> +	val = *p;
> +
> +	val = le64_to_cpu(val);
> +
> +	coll_id = val & KVM_ITS_ITE_ICID_MASK;
> +	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
> +
> +	if (!lpi_id)
> +		return 1; /* invalid entry, no choice but to scan next entry */
> +
> +	if (lpi_id < VGIC_MIN_LPI)
> +		return -EINVAL;
> +
> +	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
> +	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
> +		return -EINVAL;
> +
> +	collection = find_collection(its, coll_id);
> +	if (!collection)
> +		return -EINVAL;
> +
> +	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
> +	if (IS_ERR(ite))
> +		return PTR_ERR(ite);
> +
> +	if (its_is_collection_mapped(collection))
> +		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
> +
> +	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
> +	if (IS_ERR(irq))
> +		return PTR_ERR(irq);

Same remark as the previous patch: the its_ite structure should be freed
on failure. Otherwise, I suspect we end0up leaking memory.

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 23/24] KVM: arm64: vgic-its: Fix pending table sync
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:42     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:42 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:42 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> In its_sync_lpi_pending_table() we currently ignore the
> target_vcpu of the LPIs. We sync the pending bit found in
> the vcpu pending table even if the LPI is not targeting it.
>
> Also in vgic_its_cmd_handle_invall() we are supposed to
> read the config table data for the LPIs associated to the
> collection ID. At the moment we refresh all LPI config
> information.
>
> This patch passes a vpcu to vgic_copy_lpi_list() so that
> this latter returns a snapshot of the LPIs targeting this
> CPU and only those.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 23/24] KVM: arm64: vgic-its: Fix pending table sync
@ 2017-05-07 13:42     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:42 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> In its_sync_lpi_pending_table() we currently ignore the
> target_vcpu of the LPIs. We sync the pending bit found in
> the vcpu pending table even if the LPI is not targeting it.
>
> Also in vgic_its_cmd_handle_invall() we are supposed to
> read the config table data for the LPIs associated to the
> collection ID. At the moment we refresh all LPI config
> information.
>
> This patch passes a vpcu to vgic_copy_lpi_list() so that
> this latter returns a snapshot of the LPIs targeting this
> CPU and only those.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 24/24] KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-07 13:44     ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:44 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sat, May 06 2017 at  4:24:43 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> This patch adds a new attribute to GICV3 KVM device
> KVM_DEV_ARM_VGIC_GRP_CTRL group. This allows userspace to
> flush all GICR pending tables into guest RAM.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 24/24] KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
@ 2017-05-07 13:44     ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06 2017 at  4:24:43 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> This patch adds a new attribute to GICV3 KVM device
> KVM_DEV_ARM_VGIC_GRP_CTRL group. This allows userspace to
> flush all GICR pending tables into guest RAM.
>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> Reviewed-by: Christoffer Dall <cdall@linaro.org>

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  2017-05-07 13:00     ` Marc Zyngier
@ 2017-05-07 13:51       ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:51 UTC (permalink / raw)
  To: Eric Auger
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sun, May 07 2017 at  2:00:30 pm BST, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
>> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
>> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>>   structures.
>>
>> We hold the vcpus lock during the save and restore to make
>> sure no vcpu is running.
>>
>> At this stage the functionality is not yet implemented. Only
>> the skeleton is put in place.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>> v6 -> v7:
>> - also hold the its_lock on save and restore
>>
>> v5 -> v6:
>> - remove the pending table sync from the ITS table restore
>>
>> v4 -> v5:
>> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
>> - rename *flush* into *save*
>> - call its_sync_lpi_pending_table at the end of restore
>> - use abi framework
>>
>> v3 -> v4:
>> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
>> - take the kvm lock and vcpu locks
>> - ABI revision check
>> - check attr->attr is null
>>
>> v1 -> v2:
>> - remove useless kvm parameter
>> ---
>>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>>  3 files changed, 109 insertions(+), 6 deletions(-)
>>
>
> [...]
>
>> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>>   */
>>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>>  {
>> -	return -ENXIO;
>> +	struct kvm *kvm = its->dev->kvm;
>> +	int ret;
>> +
>> +	mutex_lock(&kvm->lock);
>> +	mutex_lock(&its->its_lock);
>> +
>> +	if (!lock_all_vcpus(kvm)) {
>> +		mutex_unlock(&its->its_lock);
>> +		mutex_unlock(&kvm->lock);
>> +		return -EBUSY;
>> +	}
>> +
>> +	ret = vgic_its_restore_collection_table(its);
>> +	if (ret)
>> +		goto out;
>> +
>> +	ret = vgic_its_restore_device_tables(its);
>> +
>> +out:
>> +	unlock_all_vcpus(kvm);
>> +	mutex_unlock(&its->its_lock);
>> +	mutex_unlock(&kvm->lock);
>> +
>> +	if (ret)
>> +		return ret;
>> +
>> +	/*
>> +	 * On restore path, MSI injections can happen before the
>> +	 * first VCPU run so let's complete the GIC init here.
>> +	 */
>> +	return kvm_vgic_map_resources(its->dev->kvm);
>
> This one is still a rather sore spot, but I've lost track of what we can
> do about it. Until now, this would only happen on first run. But it
> looks like QEMU and KVM have different views of what "runable" is.
>
> I'm not sure there is a good way to solve this, unfortunately. From a
> device PoV, everything is ready and the fact that nothing is clocking
> the CPUs is very much irrelevant. I'm almost tempted to say that the
> map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
> that we're missing a synchronization point with userspace that would say
> "system is entierely configured", triggering the iodev registration.
>
> Oh well. At that point, and short of having something better to offer:
>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
>
> 	M.

Actually, there is a rather big problem here. This function is called on
a per-ITS basis. But once we have run map_resources *once*, any other
call becomes ineffective (vgic_ready() returns true). What happens to
the other ITSs? Can they still be successfully restored? Don't they
end-up with the same "blind spot" you've tried to close?

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
@ 2017-05-07 13:51       ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-07 13:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, May 07 2017 at  2:00:30 pm BST, Marc Zyngier <marc.zyngier@arm.com> wrote:
> On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
>> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
>> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>>   structures.
>>
>> We hold the vcpus lock during the save and restore to make
>> sure no vcpu is running.
>>
>> At this stage the functionality is not yet implemented. Only
>> the skeleton is put in place.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>> v6 -> v7:
>> - also hold the its_lock on save and restore
>>
>> v5 -> v6:
>> - remove the pending table sync from the ITS table restore
>>
>> v4 -> v5:
>> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
>> - rename *flush* into *save*
>> - call its_sync_lpi_pending_table at the end of restore
>> - use abi framework
>>
>> v3 -> v4:
>> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
>> - take the kvm lock and vcpu locks
>> - ABI revision check
>> - check attr->attr is null
>>
>> v1 -> v2:
>> - remove useless kvm parameter
>> ---
>>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>>  3 files changed, 109 insertions(+), 6 deletions(-)
>>
>
> [...]
>
>> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>>   */
>>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>>  {
>> -	return -ENXIO;
>> +	struct kvm *kvm = its->dev->kvm;
>> +	int ret;
>> +
>> +	mutex_lock(&kvm->lock);
>> +	mutex_lock(&its->its_lock);
>> +
>> +	if (!lock_all_vcpus(kvm)) {
>> +		mutex_unlock(&its->its_lock);
>> +		mutex_unlock(&kvm->lock);
>> +		return -EBUSY;
>> +	}
>> +
>> +	ret = vgic_its_restore_collection_table(its);
>> +	if (ret)
>> +		goto out;
>> +
>> +	ret = vgic_its_restore_device_tables(its);
>> +
>> +out:
>> +	unlock_all_vcpus(kvm);
>> +	mutex_unlock(&its->its_lock);
>> +	mutex_unlock(&kvm->lock);
>> +
>> +	if (ret)
>> +		return ret;
>> +
>> +	/*
>> +	 * On restore path, MSI injections can happen before the
>> +	 * first VCPU run so let's complete the GIC init here.
>> +	 */
>> +	return kvm_vgic_map_resources(its->dev->kvm);
>
> This one is still a rather sore spot, but I've lost track of what we can
> do about it. Until now, this would only happen on first run. But it
> looks like QEMU and KVM have different views of what "runable" is.
>
> I'm not sure there is a good way to solve this, unfortunately. From a
> device PoV, everything is ready and the fact that nothing is clocking
> the CPUs is very much irrelevant. I'm almost tempted to say that the
> map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
> that we're missing a synchronization point with userspace that would say
> "system is entierely configured", triggering the iodev registration.
>
> Oh well. At that point, and short of having something better to offer:
>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
>
> 	M.

Actually, there is a rather big problem here. This function is called on
a per-ITS basis. But once we have run map_resources *once*, any other
call becomes ineffective (vgic_ready() returns true). What happens to
the other ITSs? Can they still be successfully restored? Don't they
end-up with the same "blind spot" you've tried to close?

Thanks,

	M.
-- 
Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  2017-05-07 13:51       ` Marc Zyngier
@ 2017-05-07 15:19         ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-07 15:19 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	bjsprakash.linux, Vijaya.Kumar, linux-arm-kernel, pbonzini,
	kvmarm, eric.auger.pro

On Sun, May 07, 2017 at 02:51:37PM +0100, Marc Zyngier wrote:
> On Sun, May 07 2017 at  2:00:30 pm BST, Marc Zyngier <marc.zyngier@arm.com> wrote:
> > On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> >> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
> >> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
> >> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
> >>   structures.
> >>
> >> We hold the vcpus lock during the save and restore to make
> >> sure no vcpu is running.
> >>
> >> At this stage the functionality is not yet implemented. Only
> >> the skeleton is put in place.
> >>
> >> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> >>
> >> ---
> >> v6 -> v7:
> >> - also hold the its_lock on save and restore
> >>
> >> v5 -> v6:
> >> - remove the pending table sync from the ITS table restore
> >>
> >> v4 -> v5:
> >> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
> >> - rename *flush* into *save*
> >> - call its_sync_lpi_pending_table at the end of restore
> >> - use abi framework
> >>
> >> v3 -> v4:
> >> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
> >> - take the kvm lock and vcpu locks
> >> - ABI revision check
> >> - check attr->attr is null
> >>
> >> v1 -> v2:
> >> - remove useless kvm parameter
> >> ---
> >>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
> >>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
> >>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
> >>  3 files changed, 109 insertions(+), 6 deletions(-)
> >>
> >
> > [...]
> >
> >> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
> >>   */
> >>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
> >>  {
> >> -	return -ENXIO;
> >> +	struct kvm *kvm = its->dev->kvm;
> >> +	int ret;
> >> +
> >> +	mutex_lock(&kvm->lock);
> >> +	mutex_lock(&its->its_lock);
> >> +
> >> +	if (!lock_all_vcpus(kvm)) {
> >> +		mutex_unlock(&its->its_lock);
> >> +		mutex_unlock(&kvm->lock);
> >> +		return -EBUSY;
> >> +	}
> >> +
> >> +	ret = vgic_its_restore_collection_table(its);
> >> +	if (ret)
> >> +		goto out;
> >> +
> >> +	ret = vgic_its_restore_device_tables(its);
> >> +
> >> +out:
> >> +	unlock_all_vcpus(kvm);
> >> +	mutex_unlock(&its->its_lock);
> >> +	mutex_unlock(&kvm->lock);
> >> +
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	/*
> >> +	 * On restore path, MSI injections can happen before the
> >> +	 * first VCPU run so let's complete the GIC init here.
> >> +	 */
> >> +	return kvm_vgic_map_resources(its->dev->kvm);
> >
> > This one is still a rather sore spot, but I've lost track of what we can
> > do about it. Until now, this would only happen on first run. But it
> > looks like QEMU and KVM have different views of what "runable" is.
> >
> > I'm not sure there is a good way to solve this, unfortunately. From a
> > device PoV, everything is ready and the fact that nothing is clocking
> > the CPUs is very much irrelevant. I'm almost tempted to say that the
> > map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
> > that we're missing a synchronization point with userspace that would say
> > "system is entierely configured", triggering the iodev registration.
> >
> > Oh well. At that point, and short of having something better to offer:
> >
> > Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> >
> > 	M.
> 
> Actually, there is a rather big problem here. This function is called on
> a per-ITS basis. But once we have run map_resources *once*, any other
> call becomes ineffective (vgic_ready() returns true). What happens to
> the other ITSs? Can they still be successfully restored? Don't they
> end-up with the same "blind spot" you've tried to close?
> 
I really think the only proper solution to this is to have map_resources
do nothing at all on GICv3, and register the iodevs when the base
addresses are set, and all that map_resources end up doing is to
actually map stuff for GICv2 in the guest address space (the virtual CPU
interface).

That way the initialization is tied to the data that makes the
initialization possible, we don't need another sync point, it becomes
ITS-specific, and migration should work.  Take two? :)

-Christoffer

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

* [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
@ 2017-05-07 15:19         ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-07 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, May 07, 2017 at 02:51:37PM +0100, Marc Zyngier wrote:
> On Sun, May 07 2017 at  2:00:30 pm BST, Marc Zyngier <marc.zyngier@arm.com> wrote:
> > On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> >> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
> >> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
> >> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
> >>   structures.
> >>
> >> We hold the vcpus lock during the save and restore to make
> >> sure no vcpu is running.
> >>
> >> At this stage the functionality is not yet implemented. Only
> >> the skeleton is put in place.
> >>
> >> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> >>
> >> ---
> >> v6 -> v7:
> >> - also hold the its_lock on save and restore
> >>
> >> v5 -> v6:
> >> - remove the pending table sync from the ITS table restore
> >>
> >> v4 -> v5:
> >> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
> >> - rename *flush* into *save*
> >> - call its_sync_lpi_pending_table at the end of restore
> >> - use abi framework
> >>
> >> v3 -> v4:
> >> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
> >> - take the kvm lock and vcpu locks
> >> - ABI revision check
> >> - check attr->attr is null
> >>
> >> v1 -> v2:
> >> - remove useless kvm parameter
> >> ---
> >>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
> >>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
> >>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
> >>  3 files changed, 109 insertions(+), 6 deletions(-)
> >>
> >
> > [...]
> >
> >> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
> >>   */
> >>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
> >>  {
> >> -	return -ENXIO;
> >> +	struct kvm *kvm = its->dev->kvm;
> >> +	int ret;
> >> +
> >> +	mutex_lock(&kvm->lock);
> >> +	mutex_lock(&its->its_lock);
> >> +
> >> +	if (!lock_all_vcpus(kvm)) {
> >> +		mutex_unlock(&its->its_lock);
> >> +		mutex_unlock(&kvm->lock);
> >> +		return -EBUSY;
> >> +	}
> >> +
> >> +	ret = vgic_its_restore_collection_table(its);
> >> +	if (ret)
> >> +		goto out;
> >> +
> >> +	ret = vgic_its_restore_device_tables(its);
> >> +
> >> +out:
> >> +	unlock_all_vcpus(kvm);
> >> +	mutex_unlock(&its->its_lock);
> >> +	mutex_unlock(&kvm->lock);
> >> +
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	/*
> >> +	 * On restore path, MSI injections can happen before the
> >> +	 * first VCPU run so let's complete the GIC init here.
> >> +	 */
> >> +	return kvm_vgic_map_resources(its->dev->kvm);
> >
> > This one is still a rather sore spot, but I've lost track of what we can
> > do about it. Until now, this would only happen on first run. But it
> > looks like QEMU and KVM have different views of what "runable" is.
> >
> > I'm not sure there is a good way to solve this, unfortunately. From a
> > device PoV, everything is ready and the fact that nothing is clocking
> > the CPUs is very much irrelevant. I'm almost tempted to say that the
> > map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
> > that we're missing a synchronization point with userspace that would say
> > "system is entierely configured", triggering the iodev registration.
> >
> > Oh well. At that point, and short of having something better to offer:
> >
> > Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> >
> > 	M.
> 
> Actually, there is a rather big problem here. This function is called on
> a per-ITS basis. But once we have run map_resources *once*, any other
> call becomes ineffective (vgic_ready() returns true). What happens to
> the other ITSs? Can they still be successfully restored? Don't they
> end-up with the same "blind spot" you've tried to close?
> 
I really think the only proper solution to this is to have map_resources
do nothing at all on GICv3, and register the iodevs when the base
addresses are set, and all that map_resources end up doing is to
actually map stuff for GICv2 in the guest address space (the virtual CPU
interface).

That way the initialization is tied to the data that makes the
initialization possible, we don't need another sync point, it becomes
ITS-specific, and migration should work.  Take two? :)

-Christoffer

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

* Re: [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
  2017-05-07 11:54     ` Marc Zyngier
@ 2017-05-07 17:05       ` Auger Eric
  -1 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:05 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	Vijaya.Kumar, pbonzini, kvmarm, linux-arm-kernel, eric.auger.pro

Hi Marc,

On 07/05/2017 13:54, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> Add description for how to access ITS registers and how to save/restore
>> ITS tables into/from memory.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>> v6 -> v7:
>> - rephrase ordering sequence + few cosmetic changes
>>
>> v5 -> v6:
>> - add restoration ordering
>> - 256B -> 256 Byte aligned
>> - DTE Size is number of bits for the EVENTID
>> - s/GITS_READR/GITS_CREADR
>>
>> v4 -> v5:
>> - take into account Christoffer's comments
>> - pending table save on GICV3 side now
>>
>> v3 -> v4:
>> - take into account Peter's comments:
>>   - typos
>>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
>>   - add a validity bit in DTE
>>   - document all fields in CTE and ITE
>>   - document ABI revision
>> - take into account Andre's comments:
>>   - document restrictions about GITS_CREADR writing and GITS_IIDR
>>   - document -EBUSY error if one or more VCPUS are runnning
>>   - document 64b registers only can be accessed with 64b access
>> - itt_addr field matches bits [51:8] of the itt_addr
>>
>> v1 -> v2:
>> - DTE and ITE now are 8 bytes
>> - DTE and ITE now indexed by deviceid/eventid
>> - use ITE name instead of ITTE
>> - mentions ITT_addr matches bits [51:8] of the actual address
>> - mentions LE layout
>> ---
>>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
>>  1 file changed, 120 insertions(+)
>>
>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>> index 6081a5b..ba132e9 100644
>> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> [...]
> 
>> + ITS Table ABI REV0:
>> + -------------------
>> +
>> + Revision 0 of the ABI only supports physical LPIs.
> 
> Nit: these are no more physical than any other interrupt that KVM deals
> with. If you're hinting at the lack of GICv4 support, it wouldn't
> necessarily invalidate this ABI. It is actually even likely that the ABI
> could stay the same (until we start supporting GICv4 in a nested
> configuration).
I understood vLPI are associated to vPE and not to collections. As such
ITE would need to be updated, wouldn't it?
> 
>> +
>> + The device table and ITT are indexed by the deviceid and eventid,
>> + respectively. The collection table is not indexed by collectionid:
>> + CTEs are written in the table in the order of collection creation. All
> 
> Is this order really relevant? Can we relax it? Would something break if
> collections were in a random order?
Christoffer asked me to mention the exact storage order or at least I
understood his comment that way. Nothing would break if we change the order.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
@ 2017-05-07 17:05       ` Auger Eric
  0 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On 07/05/2017 13:54, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> Add description for how to access ITS registers and how to save/restore
>> ITS tables into/from memory.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>> v6 -> v7:
>> - rephrase ordering sequence + few cosmetic changes
>>
>> v5 -> v6:
>> - add restoration ordering
>> - 256B -> 256 Byte aligned
>> - DTE Size is number of bits for the EVENTID
>> - s/GITS_READR/GITS_CREADR
>>
>> v4 -> v5:
>> - take into account Christoffer's comments
>> - pending table save on GICV3 side now
>>
>> v3 -> v4:
>> - take into account Peter's comments:
>>   - typos
>>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
>>   - add a validity bit in DTE
>>   - document all fields in CTE and ITE
>>   - document ABI revision
>> - take into account Andre's comments:
>>   - document restrictions about GITS_CREADR writing and GITS_IIDR
>>   - document -EBUSY error if one or more VCPUS are runnning
>>   - document 64b registers only can be accessed with 64b access
>> - itt_addr field matches bits [51:8] of the itt_addr
>>
>> v1 -> v2:
>> - DTE and ITE now are 8 bytes
>> - DTE and ITE now indexed by deviceid/eventid
>> - use ITE name instead of ITTE
>> - mentions ITT_addr matches bits [51:8] of the actual address
>> - mentions LE layout
>> ---
>>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
>>  1 file changed, 120 insertions(+)
>>
>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>> index 6081a5b..ba132e9 100644
>> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> [...]
> 
>> + ITS Table ABI REV0:
>> + -------------------
>> +
>> + Revision 0 of the ABI only supports physical LPIs.
> 
> Nit: these are no more physical than any other interrupt that KVM deals
> with. If you're hinting at the lack of GICv4 support, it wouldn't
> necessarily invalidate this ABI. It is actually even likely that the ABI
> could stay the same (until we start supporting GICv4 in a nested
> configuration).
I understood vLPI are associated to vPE and not to collections. As such
ITE would need to be updated, wouldn't it?
> 
>> +
>> + The device table and ITT are indexed by the deviceid and eventid,
>> + respectively. The collection table is not indexed by collectionid:
>> + CTEs are written in the table in the order of collection creation. All
> 
> Is this order really relevant? Can we relax it? Would something break if
> collections were in a random order?
Christoffer asked me to mention the exact storage order or at least I
understood his comment that way. Nothing would break if we change the order.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* Re: [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
  2017-05-07 13:30     ` Marc Zyngier
@ 2017-05-07 17:22       ` Auger Eric
  -1 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	Vijaya.Kumar, pbonzini, kvmarm, linux-arm-kernel, eric.auger.pro

Hi Marc,
On 07/05/2017 15:30, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:40 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> This patch saves the device table entries into guest RAM.
>> Both flat table and 2 stage tables are supported. DeviceId
>> indexing is used.
>>
>> For each device listed in the device table, we also save
>> the translation table using the vgic_its_save/restore_itt
>> routines. Those functions will be implemented in a subsequent
>> patch.
>>
>> On restore, devices are re-allocated and their itt are
>> re-built.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>> v5 -> v6:
>> - accomodate vgic_its_alloc_device change of proto
>> - define bit fields for L1 entries
>> - s/handle_l1_entry/handle_l1_dte
>> - s/ite_esz/dte_esz in handle_l1_dte
>> - check BASER valid bit
>> - s/nb_eventid_bits/num_eventid_bits
>> - new convention for returned values
>> - itt functions implemented in subsequent patch
>>
>> v4 -> v5:
>> - sort the device list by deviceid on device table save
>> - use defines for shifts and masks
>> - use abi->dte_esz
>> - clatify entry sizes for L1 and L2 tables
>>
>> v3 -> v4:
>> - use the new proto for its_alloc_device
>> - compute_next_devid_offset, vgic_its_flush/restore_itt
>>   become static in this patch
>> - change in the DTE entry format with the introduction of the
>>   valid bit and next field width decrease; ittaddr encoded
>>   on its full range
>> - fix handle_l1_entry entry handling
>> - correct vgic_its_table_restore error handling
>>
>> v2 -> v3:
>> - fix itt_addr bitmask in vgic_its_restore_dte
>> - addition of return 0 in vgic_its_restore_ite moved to
>>   the ITE related patch
>>
>> v1 -> v2:
>> - use 8 byte format for DTE and ITE
>> - support 2 stage format
>> - remove kvm parameter
>> - ITT flush/restore moved in a separate patch
>> - use deviceid indexing
>> ---
>>  virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic.h     |  10 +++
>>  2 files changed, 199 insertions(+), 5 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
>> index 90afc83..3dea626 100644
>> --- a/virt/kvm/arm/vgic/vgic-its.c
>> +++ b/virt/kvm/arm/vgic/vgic-its.c
>> @@ -23,6 +23,7 @@
>>  #include <linux/interrupt.h>
>>  #include <linux/list.h>
>>  #include <linux/uaccess.h>
>> +#include <linux/list_sort.h>
>>  
>>  #include <linux/irqchip/arm-gic-v3.h>
>>  
>> @@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
>>  	return ret;
>>  }
>>  
>> -u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
>> +static u32 compute_next_devid_offset(struct list_head *h,
>> +				     struct its_device *dev)
>>  {
>>  	struct its_device *next;
>>  	u32 next_offset;
>> @@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
>>   * Return: < 0 on error, 0 if last element was identified, 1 otherwise
>>   * (the last element may not be found on second level tables)
>>   */
>> -int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>> -		   int start_id, entry_fn_t fn, void *opaque)
>> +static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>> +			  int start_id, entry_fn_t fn, void *opaque)
>>  {
>>  	void *entry = kzalloc(esz, GFP_KERNEL);
>>  	struct kvm *kvm = its->dev->kvm;
>> @@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>>  	return ret;
>>  }
>>  
>> +static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +/**
>> + * vgic_its_save_dte - Save a device table entry at a given GPA
>> + *
>> + * @its: ITS handle
>> + * @dev: ITS device
>> + * @ptr: GPA
>> + */
>> +static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
>> +			     gpa_t ptr, int dte_esz)
>> +{
>> +	struct kvm *kvm = its->dev->kvm;
>> +	u64 val, itt_addr_field;
>> +	u32 next_offset;
>> +
>> +	itt_addr_field = dev->itt_addr >> 8;
>> +	next_offset = compute_next_devid_offset(&its->device_list, dev);
>> +	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
>> +	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
>> +	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
>> +		(dev->num_eventid_bits - 1));
>> +	val = cpu_to_le64(val);
>> +	return kvm_write_guest(kvm, ptr, &val, dte_esz);
>> +}
>> +
>> +/**
>> + * vgic_its_restore_dte - restore a device table entry
>> + *
>> + * @its: its handle
>> + * @id: device id the DTE corresponds to
>> + * @ptr: kernel VA where the 8 byte DTE is located
>> + * @opaque: unused
>> + *
>> + * Return: < 0 on error, 0 if the dte is the last one, id offset to the
>> + * next dte otherwise
>> + */
>> +static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
>> +				void *ptr, void *opaque)
>> +{
>> +	struct its_device *dev;
>> +	gpa_t itt_addr;
>> +	u8 num_eventid_bits;
>> +	u64 entry = *(u64 *)ptr;
>> +	bool valid;
>> +	u32 offset;
>> +	int ret;
>> +
>> +	entry = le64_to_cpu(entry);
>> +
>> +	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
>> +	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
>> +	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
>> +			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
>> +
>> +	if (!valid)
>> +		return 1;
>> +
>> +	/* dte entry is valid */
>> +	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
>> +
>> +	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
>> +	if (IS_ERR(dev))
>> +		return PTR_ERR(dev);
>> +
>> +	ret = vgic_its_restore_itt(its, dev);
>> +	if (ret)
>> +		return ret;
> 
> Shouldn't we free the device entry if the restore as failed?
This is not totally obvious to me. the device creation is the result of
MAPD. The ITT is populated by MAPI's. Besides vgic_its_destroy frees
everything so I don't think there is any leak eventually. But if you
prefer I will do it.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
@ 2017-05-07 17:22       ` Auger Eric
  0 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,
On 07/05/2017 15:30, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:40 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> This patch saves the device table entries into guest RAM.
>> Both flat table and 2 stage tables are supported. DeviceId
>> indexing is used.
>>
>> For each device listed in the device table, we also save
>> the translation table using the vgic_its_save/restore_itt
>> routines. Those functions will be implemented in a subsequent
>> patch.
>>
>> On restore, devices are re-allocated and their itt are
>> re-built.
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>> v5 -> v6:
>> - accomodate vgic_its_alloc_device change of proto
>> - define bit fields for L1 entries
>> - s/handle_l1_entry/handle_l1_dte
>> - s/ite_esz/dte_esz in handle_l1_dte
>> - check BASER valid bit
>> - s/nb_eventid_bits/num_eventid_bits
>> - new convention for returned values
>> - itt functions implemented in subsequent patch
>>
>> v4 -> v5:
>> - sort the device list by deviceid on device table save
>> - use defines for shifts and masks
>> - use abi->dte_esz
>> - clatify entry sizes for L1 and L2 tables
>>
>> v3 -> v4:
>> - use the new proto for its_alloc_device
>> - compute_next_devid_offset, vgic_its_flush/restore_itt
>>   become static in this patch
>> - change in the DTE entry format with the introduction of the
>>   valid bit and next field width decrease; ittaddr encoded
>>   on its full range
>> - fix handle_l1_entry entry handling
>> - correct vgic_its_table_restore error handling
>>
>> v2 -> v3:
>> - fix itt_addr bitmask in vgic_its_restore_dte
>> - addition of return 0 in vgic_its_restore_ite moved to
>>   the ITE related patch
>>
>> v1 -> v2:
>> - use 8 byte format for DTE and ITE
>> - support 2 stage format
>> - remove kvm parameter
>> - ITT flush/restore moved in a separate patch
>> - use deviceid indexing
>> ---
>>  virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic.h     |  10 +++
>>  2 files changed, 199 insertions(+), 5 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
>> index 90afc83..3dea626 100644
>> --- a/virt/kvm/arm/vgic/vgic-its.c
>> +++ b/virt/kvm/arm/vgic/vgic-its.c
>> @@ -23,6 +23,7 @@
>>  #include <linux/interrupt.h>
>>  #include <linux/list.h>
>>  #include <linux/uaccess.h>
>> +#include <linux/list_sort.h>
>>  
>>  #include <linux/irqchip/arm-gic-v3.h>
>>  
>> @@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
>>  	return ret;
>>  }
>>  
>> -u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
>> +static u32 compute_next_devid_offset(struct list_head *h,
>> +				     struct its_device *dev)
>>  {
>>  	struct its_device *next;
>>  	u32 next_offset;
>> @@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
>>   * Return: < 0 on error, 0 if last element was identified, 1 otherwise
>>   * (the last element may not be found on second level tables)
>>   */
>> -int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>> -		   int start_id, entry_fn_t fn, void *opaque)
>> +static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>> +			  int start_id, entry_fn_t fn, void *opaque)
>>  {
>>  	void *entry = kzalloc(esz, GFP_KERNEL);
>>  	struct kvm *kvm = its->dev->kvm;
>> @@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>>  	return ret;
>>  }
>>  
>> +static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
>> +{
>> +	return -ENXIO;
>> +}
>> +
>> +/**
>> + * vgic_its_save_dte - Save a device table entry at a given GPA
>> + *
>> + * @its: ITS handle
>> + * @dev: ITS device
>> + * @ptr: GPA
>> + */
>> +static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
>> +			     gpa_t ptr, int dte_esz)
>> +{
>> +	struct kvm *kvm = its->dev->kvm;
>> +	u64 val, itt_addr_field;
>> +	u32 next_offset;
>> +
>> +	itt_addr_field = dev->itt_addr >> 8;
>> +	next_offset = compute_next_devid_offset(&its->device_list, dev);
>> +	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
>> +	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
>> +	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
>> +		(dev->num_eventid_bits - 1));
>> +	val = cpu_to_le64(val);
>> +	return kvm_write_guest(kvm, ptr, &val, dte_esz);
>> +}
>> +
>> +/**
>> + * vgic_its_restore_dte - restore a device table entry
>> + *
>> + * @its: its handle
>> + * @id: device id the DTE corresponds to
>> + * @ptr: kernel VA where the 8 byte DTE is located
>> + * @opaque: unused
>> + *
>> + * Return: < 0 on error, 0 if the dte is the last one, id offset to the
>> + * next dte otherwise
>> + */
>> +static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
>> +				void *ptr, void *opaque)
>> +{
>> +	struct its_device *dev;
>> +	gpa_t itt_addr;
>> +	u8 num_eventid_bits;
>> +	u64 entry = *(u64 *)ptr;
>> +	bool valid;
>> +	u32 offset;
>> +	int ret;
>> +
>> +	entry = le64_to_cpu(entry);
>> +
>> +	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
>> +	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
>> +	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
>> +			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
>> +
>> +	if (!valid)
>> +		return 1;
>> +
>> +	/* dte entry is valid */
>> +	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
>> +
>> +	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
>> +	if (IS_ERR(dev))
>> +		return PTR_ERR(dev);
>> +
>> +	ret = vgic_its_restore_itt(its, dev);
>> +	if (ret)
>> +		return ret;
> 
> Shouldn't we free the device entry if the restore as failed?
This is not totally obvious to me. the device creation is the result of
MAPD. The ITT is populated by MAPI's. Besides vgic_its_destroy frees
everything so I don't think there is any leak eventually. But if you
prefer I will do it.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* Re: [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
  2017-05-07 13:39     ` Marc Zyngier
@ 2017-05-07 17:24       ` Auger Eric
  -1 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:24 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	Vijaya.Kumar, pbonzini, kvmarm, linux-arm-kernel, eric.auger.pro



On 07/05/2017 15:39, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:41 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> Implement routines to save and restore device ITT and their
>> interrupt table entries (ITE).
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>> Reviewed-by: Christoffer Dall <cdall@linaro.org>
>>
>> ---
>> v6 -> v7:
>> - added Christoffer's R-b
>>
>> v5 -> v6:
>> - accomodate vgic_its_alloc_ite change of proto
>> - check LPI ID on restore, check eventid offset
>> - initializations on separate line
>> - coming after device save/restore
>> - add_lpi does config and pending bit sync
>>
>> v4 -> v5:
>> - ITE are now sorted by eventid on the flush
>> - rename *flush* into *save*
>> - use macros for shits and masks
>> - pass ite_esz to vgic_its_save_ite
>>
>> v3 -> v4:
>> - lookup_table and compute_next_eventid_offset become static in this
>>   patch
>> - remove static along with vgic_its_flush/restore_itt to avoid
>>   compilation warnings
>> - next field only computed with a shift (mask removed)
>> - handle the case where the last element has not been found
>>
>> v2 -> v3:
>> - add return 0 in vgic_its_restore_ite (was in subsequent patch)
>>
>> v2: creation
>> ---
>>  virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic.h     |   4 ++
>>  2 files changed, 117 insertions(+), 3 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
>> index 3dea626..adb3d9e 100644
>> --- a/virt/kvm/arm/vgic/vgic-its.c
>> +++ b/virt/kvm/arm/vgic/vgic-its.c
>> @@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
>>  	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
>>  }
>>  
>> -u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
>> +static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
>>  {
>>  	struct its_ite *next;
>>  	u32 next_offset;
>> @@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>>  	return ret;
>>  }
>>  
>> +/**
>> + * vgic_its_save_ite - Save an interrupt translation entry at @gpa
>> + */
>> +static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
>> +			      struct its_ite *ite, gpa_t gpa, int ite_esz)
>> +{
>> +	struct kvm *kvm = its->dev->kvm;
>> +	u32 next_offset;
>> +	u64 val;
>> +
>> +	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
>> +	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
>> +	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
>> +		ite->collection->collection_id;
>> +	val = cpu_to_le64(val);
>> +	return kvm_write_guest(kvm, gpa, &val, ite_esz);
>> +}
>> +
>> +/**
>> + * vgic_its_restore_ite - restore an interrupt translation entry
>> + * @event_id: id used for indexing
>> + * @ptr: pointer to the ITE entry
>> + * @opaque: pointer to the its_device
>> + */
>> +static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
>> +				void *ptr, void *opaque)
>> +{
>> +	struct its_device *dev = (struct its_device *)opaque;
>> +	struct its_collection *collection;
>> +	struct kvm *kvm = its->dev->kvm;
>> +	struct kvm_vcpu *vcpu = NULL;
>> +	u64 val;
>> +	u64 *p = (u64 *)ptr;
>> +	struct vgic_irq *irq;
>> +	u32 coll_id, lpi_id;
>> +	struct its_ite *ite;
>> +	u32 offset;
>> +
>> +	val = *p;
>> +
>> +	val = le64_to_cpu(val);
>> +
>> +	coll_id = val & KVM_ITS_ITE_ICID_MASK;
>> +	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
>> +
>> +	if (!lpi_id)
>> +		return 1; /* invalid entry, no choice but to scan next entry */
>> +
>> +	if (lpi_id < VGIC_MIN_LPI)
>> +		return -EINVAL;
>> +
>> +	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
>> +	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
>> +		return -EINVAL;
>> +
>> +	collection = find_collection(its, coll_id);
>> +	if (!collection)
>> +		return -EINVAL;
>> +
>> +	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
>> +	if (IS_ERR(ite))
>> +		return PTR_ERR(ite);
>> +
>> +	if (its_is_collection_mapped(collection))
>> +		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
>> +
>> +	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
>> +	if (IS_ERR(irq))
>> +		return PTR_ERR(irq);
> 
> Same remark as the previous patch: the its_ite structure should be freed
> on failure. Otherwise, I suspect we end0up leaking memory.
also freed in vgic_its_destroy.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
@ 2017-05-07 17:24       ` Auger Eric
  0 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:24 UTC (permalink / raw)
  To: linux-arm-kernel



On 07/05/2017 15:39, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:41 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>> Implement routines to save and restore device ITT and their
>> interrupt table entries (ITE).
>>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>> Reviewed-by: Christoffer Dall <cdall@linaro.org>
>>
>> ---
>> v6 -> v7:
>> - added Christoffer's R-b
>>
>> v5 -> v6:
>> - accomodate vgic_its_alloc_ite change of proto
>> - check LPI ID on restore, check eventid offset
>> - initializations on separate line
>> - coming after device save/restore
>> - add_lpi does config and pending bit sync
>>
>> v4 -> v5:
>> - ITE are now sorted by eventid on the flush
>> - rename *flush* into *save*
>> - use macros for shits and masks
>> - pass ite_esz to vgic_its_save_ite
>>
>> v3 -> v4:
>> - lookup_table and compute_next_eventid_offset become static in this
>>   patch
>> - remove static along with vgic_its_flush/restore_itt to avoid
>>   compilation warnings
>> - next field only computed with a shift (mask removed)
>> - handle the case where the last element has not been found
>>
>> v2 -> v3:
>> - add return 0 in vgic_its_restore_ite (was in subsequent patch)
>>
>> v2: creation
>> ---
>>  virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
>>  virt/kvm/arm/vgic/vgic.h     |   4 ++
>>  2 files changed, 117 insertions(+), 3 deletions(-)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
>> index 3dea626..adb3d9e 100644
>> --- a/virt/kvm/arm/vgic/vgic-its.c
>> +++ b/virt/kvm/arm/vgic/vgic-its.c
>> @@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
>>  	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
>>  }
>>  
>> -u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
>> +static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
>>  {
>>  	struct its_ite *next;
>>  	u32 next_offset;
>> @@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
>>  	return ret;
>>  }
>>  
>> +/**
>> + * vgic_its_save_ite - Save an interrupt translation entry at @gpa
>> + */
>> +static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
>> +			      struct its_ite *ite, gpa_t gpa, int ite_esz)
>> +{
>> +	struct kvm *kvm = its->dev->kvm;
>> +	u32 next_offset;
>> +	u64 val;
>> +
>> +	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
>> +	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
>> +	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
>> +		ite->collection->collection_id;
>> +	val = cpu_to_le64(val);
>> +	return kvm_write_guest(kvm, gpa, &val, ite_esz);
>> +}
>> +
>> +/**
>> + * vgic_its_restore_ite - restore an interrupt translation entry
>> + * @event_id: id used for indexing
>> + * @ptr: pointer to the ITE entry
>> + * @opaque: pointer to the its_device
>> + */
>> +static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
>> +				void *ptr, void *opaque)
>> +{
>> +	struct its_device *dev = (struct its_device *)opaque;
>> +	struct its_collection *collection;
>> +	struct kvm *kvm = its->dev->kvm;
>> +	struct kvm_vcpu *vcpu = NULL;
>> +	u64 val;
>> +	u64 *p = (u64 *)ptr;
>> +	struct vgic_irq *irq;
>> +	u32 coll_id, lpi_id;
>> +	struct its_ite *ite;
>> +	u32 offset;
>> +
>> +	val = *p;
>> +
>> +	val = le64_to_cpu(val);
>> +
>> +	coll_id = val & KVM_ITS_ITE_ICID_MASK;
>> +	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
>> +
>> +	if (!lpi_id)
>> +		return 1; /* invalid entry, no choice but to scan next entry */
>> +
>> +	if (lpi_id < VGIC_MIN_LPI)
>> +		return -EINVAL;
>> +
>> +	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
>> +	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
>> +		return -EINVAL;
>> +
>> +	collection = find_collection(its, coll_id);
>> +	if (!collection)
>> +		return -EINVAL;
>> +
>> +	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
>> +	if (IS_ERR(ite))
>> +		return PTR_ERR(ite);
>> +
>> +	if (its_is_collection_mapped(collection))
>> +		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
>> +
>> +	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
>> +	if (IS_ERR(irq))
>> +		return PTR_ERR(irq);
> 
> Same remark as the previous patch: the its_ite structure should be freed
> on failure. Otherwise, I suspect we end0up leaking memory.
also freed in vgic_its_destroy.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* Re: [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  2017-05-07 13:51       ` Marc Zyngier
@ 2017-05-07 17:33         ` Auger Eric
  -1 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:33 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, Prasun.Kapoor, vijayak, andre.przywara, quintela, dgilbert,
	Vijaya.Kumar, pbonzini, kvmarm, linux-arm-kernel, eric.auger.pro

Hi,

On 07/05/2017 15:51, Marc Zyngier wrote:
> On Sun, May 07 2017 at  2:00:30 pm BST, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>>> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
>>> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
>>> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>>>   structures.
>>>
>>> We hold the vcpus lock during the save and restore to make
>>> sure no vcpu is running.
>>>
>>> At this stage the functionality is not yet implemented. Only
>>> the skeleton is put in place.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>
>>> ---
>>> v6 -> v7:
>>> - also hold the its_lock on save and restore
>>>
>>> v5 -> v6:
>>> - remove the pending table sync from the ITS table restore
>>>
>>> v4 -> v5:
>>> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
>>> - rename *flush* into *save*
>>> - call its_sync_lpi_pending_table at the end of restore
>>> - use abi framework
>>>
>>> v3 -> v4:
>>> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
>>> - take the kvm lock and vcpu locks
>>> - ABI revision check
>>> - check attr->attr is null
>>>
>>> v1 -> v2:
>>> - remove useless kvm parameter
>>> ---
>>>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>>>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>>>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>>>  3 files changed, 109 insertions(+), 6 deletions(-)
>>>
>>
>> [...]
>>
>>> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>>>   */
>>>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>>>  {
>>> -	return -ENXIO;
>>> +	struct kvm *kvm = its->dev->kvm;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&kvm->lock);
>>> +	mutex_lock(&its->its_lock);
>>> +
>>> +	if (!lock_all_vcpus(kvm)) {
>>> +		mutex_unlock(&its->its_lock);
>>> +		mutex_unlock(&kvm->lock);
>>> +		return -EBUSY;
>>> +	}
>>> +
>>> +	ret = vgic_its_restore_collection_table(its);
>>> +	if (ret)
>>> +		goto out;
>>> +
>>> +	ret = vgic_its_restore_device_tables(its);
>>> +
>>> +out:
>>> +	unlock_all_vcpus(kvm);
>>> +	mutex_unlock(&its->its_lock);
>>> +	mutex_unlock(&kvm->lock);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	/*
>>> +	 * On restore path, MSI injections can happen before the
>>> +	 * first VCPU run so let's complete the GIC init here.
>>> +	 */
>>> +	return kvm_vgic_map_resources(its->dev->kvm);
>>
>> This one is still a rather sore spot, but I've lost track of what we can
>> do about it. Until now, this would only happen on first run. But it
>> looks like QEMU and KVM have different views of what "runable" is.
>>
>> I'm not sure there is a good way to solve this, unfortunately. From a
>> device PoV, everything is ready and the fact that nothing is clocking
>> the CPUs is very much irrelevant. I'm almost tempted to say that the
>> map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
>> that we're missing a synchronization point with userspace that would say
>> "system is entierely configured", triggering the iodev registration.
>>
>> Oh well. At that point, and short of having something better to offer:
>>
>> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
>>
>> 	M.
> 
> Actually, there is a rather big problem here. This function is called on
> a per-ITS basis. But once we have run map_resources *once*, any other
> call becomes ineffective (vgic_ready() returns true). What happens to
> the other ITSs? Can they still be successfully restored? Don't they
> end-up with the same "blind spot" you've tried to close?

The 1st call to map_resources() maps GICV3 regs and also maps all ITSes.
So I don't think the problem comes from the fact subsequent calls are
inefficient (and return 0) but that for this 1st call to succeeds all
ITS base addresses must have been provided by the userspace. Otherwise
this restoration of this ITS will fail. So this is not explicitly
documented that way in the ABI doc.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
@ 2017-05-07 17:33         ` Auger Eric
  0 siblings, 0 replies; 110+ messages in thread
From: Auger Eric @ 2017-05-07 17:33 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 07/05/2017 15:51, Marc Zyngier wrote:
> On Sun, May 07 2017 at  2:00:30 pm BST, Marc Zyngier <marc.zyngier@arm.com> wrote:
>> On Sat, May 06 2017 at  4:24:35 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>>> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
>>> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
>>> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>>>   structures.
>>>
>>> We hold the vcpus lock during the save and restore to make
>>> sure no vcpu is running.
>>>
>>> At this stage the functionality is not yet implemented. Only
>>> the skeleton is put in place.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>
>>> ---
>>> v6 -> v7:
>>> - also hold the its_lock on save and restore
>>>
>>> v5 -> v6:
>>> - remove the pending table sync from the ITS table restore
>>>
>>> v4 -> v5:
>>> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
>>> - rename *flush* into *save*
>>> - call its_sync_lpi_pending_table at the end of restore
>>> - use abi framework
>>>
>>> v3 -> v4:
>>> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
>>> - take the kvm lock and vcpu locks
>>> - ABI revision check
>>> - check attr->attr is null
>>>
>>> v1 -> v2:
>>> - remove useless kvm parameter
>>> ---
>>>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>>>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>>>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>>>  3 files changed, 109 insertions(+), 6 deletions(-)
>>>
>>
>> [...]
>>
>>> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>>>   */
>>>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>>>  {
>>> -	return -ENXIO;
>>> +	struct kvm *kvm = its->dev->kvm;
>>> +	int ret;
>>> +
>>> +	mutex_lock(&kvm->lock);
>>> +	mutex_lock(&its->its_lock);
>>> +
>>> +	if (!lock_all_vcpus(kvm)) {
>>> +		mutex_unlock(&its->its_lock);
>>> +		mutex_unlock(&kvm->lock);
>>> +		return -EBUSY;
>>> +	}
>>> +
>>> +	ret = vgic_its_restore_collection_table(its);
>>> +	if (ret)
>>> +		goto out;
>>> +
>>> +	ret = vgic_its_restore_device_tables(its);
>>> +
>>> +out:
>>> +	unlock_all_vcpus(kvm);
>>> +	mutex_unlock(&its->its_lock);
>>> +	mutex_unlock(&kvm->lock);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	/*
>>> +	 * On restore path, MSI injections can happen before the
>>> +	 * first VCPU run so let's complete the GIC init here.
>>> +	 */
>>> +	return kvm_vgic_map_resources(its->dev->kvm);
>>
>> This one is still a rather sore spot, but I've lost track of what we can
>> do about it. Until now, this would only happen on first run. But it
>> looks like QEMU and KVM have different views of what "runable" is.
>>
>> I'm not sure there is a good way to solve this, unfortunately. From a
>> device PoV, everything is ready and the fact that nothing is clocking
>> the CPUs is very much irrelevant. I'm almost tempted to say that the
>> map_resource() call in kvm_vcpu_first_run_init shouldn't be there, and
>> that we're missing a synchronization point with userspace that would say
>> "system is entierely configured", triggering the iodev registration.
>>
>> Oh well. At that point, and short of having something better to offer:
>>
>> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
>>
>> 	M.
> 
> Actually, there is a rather big problem here. This function is called on
> a per-ITS basis. But once we have run map_resources *once*, any other
> call becomes ineffective (vgic_ready() returns true). What happens to
> the other ITSs? Can they still be successfully restored? Don't they
> end-up with the same "blind spot" you've tried to close?

The 1st call to map_resources() maps GICV3 regs and also maps all ITSes.
So I don't think the problem comes from the fact subsequent calls are
inefficient (and return 0) but that for this 1st call to succeeds all
ITS base addresses must have been provided by the userspace. Otherwise
this restoration of this ITS will fail. So this is not explicitly
documented that way in the ABI doc.

Thanks

Eric
> 
> Thanks,
> 
> 	M.
> 

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

* Re: [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
  2017-05-07 17:05       ` Auger Eric
@ 2017-05-08  9:14         ` Marc Zyngier
  -1 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-08  9:14 UTC (permalink / raw)
  To: Auger Eric
  Cc: peter.maydell, drjones, kvm, Prasun.Kapoor, vijayak,
	andre.przywara, quintela, dgilbert, Vijaya.Kumar,
	linux-arm-kernel, pbonzini, kvmarm, christoffer.dall,
	eric.auger.pro

On 07/05/17 18:05, Auger Eric wrote:
> Hi Marc,
> 
> On 07/05/2017 13:54, Marc Zyngier wrote:
>> On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>>> Add description for how to access ITS registers and how to save/restore
>>> ITS tables into/from memory.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>
>>> ---
>>> v6 -> v7:
>>> - rephrase ordering sequence + few cosmetic changes
>>>
>>> v5 -> v6:
>>> - add restoration ordering
>>> - 256B -> 256 Byte aligned
>>> - DTE Size is number of bits for the EVENTID
>>> - s/GITS_READR/GITS_CREADR
>>>
>>> v4 -> v5:
>>> - take into account Christoffer's comments
>>> - pending table save on GICV3 side now
>>>
>>> v3 -> v4:
>>> - take into account Peter's comments:
>>>   - typos
>>>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
>>>   - add a validity bit in DTE
>>>   - document all fields in CTE and ITE
>>>   - document ABI revision
>>> - take into account Andre's comments:
>>>   - document restrictions about GITS_CREADR writing and GITS_IIDR
>>>   - document -EBUSY error if one or more VCPUS are runnning
>>>   - document 64b registers only can be accessed with 64b access
>>> - itt_addr field matches bits [51:8] of the itt_addr
>>>
>>> v1 -> v2:
>>> - DTE and ITE now are 8 bytes
>>> - DTE and ITE now indexed by deviceid/eventid
>>> - use ITE name instead of ITTE
>>> - mentions ITT_addr matches bits [51:8] of the actual address
>>> - mentions LE layout
>>> ---
>>>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
>>>  1 file changed, 120 insertions(+)
>>>
>>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>>> index 6081a5b..ba132e9 100644
>>> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>>> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>> [...]
>>
>>> + ITS Table ABI REV0:
>>> + -------------------
>>> +
>>> + Revision 0 of the ABI only supports physical LPIs.
>>
>> Nit: these are no more physical than any other interrupt that KVM deals
>> with. If you're hinting at the lack of GICv4 support, it wouldn't
>> necessarily invalidate this ABI. It is actually even likely that the ABI
>> could stay the same (until we start supporting GICv4 in a nested
>> configuration).
> I understood vLPI are associated to vPE and not to collections. As such
> ITE would need to be updated, wouldn't it?

Even in a GICv4 setup (and ignoring nesting), a guest would only see a
normal GICv3, as all the GICv4 state is the hypervisor's business, and
not something meaningful to the guest. Also, it is very desirable to be
able to migrate a GICv4 setup to a GICv3 setup without breaking everything.

To precisely answer your question, the VPE setup is done by finding out
which collection is mapped to which vcpu, and using that to map VLPIs to
VPEs. None of that is observable by the guest.

>>
>>> +
>>> + The device table and ITT are indexed by the deviceid and eventid,
>>> + respectively. The collection table is not indexed by collectionid:
>>> + CTEs are written in the table in the order of collection creation. All
>>
>> Is this order really relevant? Can we relax it? Would something break if
>> collections were in a random order?
> Christoffer asked me to mention the exact storage order or at least I
> understood his comment that way. Nothing would break if we change the order.

OK. If that's not a requirement, then we should probably drop it.

Christoffer, what do you think?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
@ 2017-05-08  9:14         ` Marc Zyngier
  0 siblings, 0 replies; 110+ messages in thread
From: Marc Zyngier @ 2017-05-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/05/17 18:05, Auger Eric wrote:
> Hi Marc,
> 
> On 07/05/2017 13:54, Marc Zyngier wrote:
>> On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
>>> Add description for how to access ITS registers and how to save/restore
>>> ITS tables into/from memory.
>>>
>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>
>>> ---
>>> v6 -> v7:
>>> - rephrase ordering sequence + few cosmetic changes
>>>
>>> v5 -> v6:
>>> - add restoration ordering
>>> - 256B -> 256 Byte aligned
>>> - DTE Size is number of bits for the EVENTID
>>> - s/GITS_READR/GITS_CREADR
>>>
>>> v4 -> v5:
>>> - take into account Christoffer's comments
>>> - pending table save on GICV3 side now
>>>
>>> v3 -> v4:
>>> - take into account Peter's comments:
>>>   - typos
>>>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
>>>   - add a validity bit in DTE
>>>   - document all fields in CTE and ITE
>>>   - document ABI revision
>>> - take into account Andre's comments:
>>>   - document restrictions about GITS_CREADR writing and GITS_IIDR
>>>   - document -EBUSY error if one or more VCPUS are runnning
>>>   - document 64b registers only can be accessed with 64b access
>>> - itt_addr field matches bits [51:8] of the itt_addr
>>>
>>> v1 -> v2:
>>> - DTE and ITE now are 8 bytes
>>> - DTE and ITE now indexed by deviceid/eventid
>>> - use ITE name instead of ITTE
>>> - mentions ITT_addr matches bits [51:8] of the actual address
>>> - mentions LE layout
>>> ---
>>>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
>>>  1 file changed, 120 insertions(+)
>>>
>>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>>> index 6081a5b..ba132e9 100644
>>> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>>> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
>> [...]
>>
>>> + ITS Table ABI REV0:
>>> + -------------------
>>> +
>>> + Revision 0 of the ABI only supports physical LPIs.
>>
>> Nit: these are no more physical than any other interrupt that KVM deals
>> with. If you're hinting at the lack of GICv4 support, it wouldn't
>> necessarily invalidate this ABI. It is actually even likely that the ABI
>> could stay the same (until we start supporting GICv4 in a nested
>> configuration).
> I understood vLPI are associated to vPE and not to collections. As such
> ITE would need to be updated, wouldn't it?

Even in a GICv4 setup (and ignoring nesting), a guest would only see a
normal GICv3, as all the GICv4 state is the hypervisor's business, and
not something meaningful to the guest. Also, it is very desirable to be
able to migrate a GICv4 setup to a GICv3 setup without breaking everything.

To precisely answer your question, the VPE setup is done by finding out
which collection is mapped to which vcpu, and using that to map VLPIs to
VPEs. None of that is observable by the guest.

>>
>>> +
>>> + The device table and ITT are indexed by the deviceid and eventid,
>>> + respectively. The collection table is not indexed by collectionid:
>>> + CTEs are written in the table in the order of collection creation. All
>>
>> Is this order really relevant? Can we relax it? Would something break if
>> collections were in a random order?
> Christoffer asked me to mention the exact storage order or at least I
> understood his comment that way. Nothing would break if we change the order.

OK. If that's not a requirement, then we should probably drop it.

Christoffer, what do you think?

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

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

* Re: [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
  2017-05-08  9:14         ` Marc Zyngier
@ 2017-05-08 11:21           ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 11:21 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Prasun.Kapoor, kvm, vijayak, andre.przywara, quintela, dgilbert,
	Vijaya.Kumar, pbonzini, kvmarm, linux-arm-kernel, eric.auger.pro

On Mon, May 08, 2017 at 10:14:21AM +0100, Marc Zyngier wrote:
> On 07/05/17 18:05, Auger Eric wrote:
> > Hi Marc,
> > 
> > On 07/05/2017 13:54, Marc Zyngier wrote:
> >> On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> >>> Add description for how to access ITS registers and how to save/restore
> >>> ITS tables into/from memory.
> >>>
> >>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> >>>
> >>> ---
> >>> v6 -> v7:
> >>> - rephrase ordering sequence + few cosmetic changes
> >>>
> >>> v5 -> v6:
> >>> - add restoration ordering
> >>> - 256B -> 256 Byte aligned
> >>> - DTE Size is number of bits for the EVENTID
> >>> - s/GITS_READR/GITS_CREADR
> >>>
> >>> v4 -> v5:
> >>> - take into account Christoffer's comments
> >>> - pending table save on GICV3 side now
> >>>
> >>> v3 -> v4:
> >>> - take into account Peter's comments:
> >>>   - typos
> >>>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
> >>>   - add a validity bit in DTE
> >>>   - document all fields in CTE and ITE
> >>>   - document ABI revision
> >>> - take into account Andre's comments:
> >>>   - document restrictions about GITS_CREADR writing and GITS_IIDR
> >>>   - document -EBUSY error if one or more VCPUS are runnning
> >>>   - document 64b registers only can be accessed with 64b access
> >>> - itt_addr field matches bits [51:8] of the itt_addr
> >>>
> >>> v1 -> v2:
> >>> - DTE and ITE now are 8 bytes
> >>> - DTE and ITE now indexed by deviceid/eventid
> >>> - use ITE name instead of ITTE
> >>> - mentions ITT_addr matches bits [51:8] of the actual address
> >>> - mentions LE layout
> >>> ---
> >>>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
> >>>  1 file changed, 120 insertions(+)
> >>>
> >>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> >>> index 6081a5b..ba132e9 100644
> >>> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> >>> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> >> [...]
> >>
> >>> + ITS Table ABI REV0:
> >>> + -------------------
> >>> +
> >>> + Revision 0 of the ABI only supports physical LPIs.
> >>
> >> Nit: these are no more physical than any other interrupt that KVM deals
> >> with. If you're hinting at the lack of GICv4 support, it wouldn't
> >> necessarily invalidate this ABI. It is actually even likely that the ABI
> >> could stay the same (until we start supporting GICv4 in a nested
> >> configuration).
> > I understood vLPI are associated to vPE and not to collections. As such
> > ITE would need to be updated, wouldn't it?
> 
> Even in a GICv4 setup (and ignoring nesting), a guest would only see a
> normal GICv3, as all the GICv4 state is the hypervisor's business, and
> not something meaningful to the guest. Also, it is very desirable to be
> able to migrate a GICv4 setup to a GICv3 setup without breaking everything.
> 
> To precisely answer your question, the VPE setup is done by finding out
> which collection is mapped to which vcpu, and using that to map VLPIs to
> VPEs. None of that is observable by the guest.
> 

Doesn't GICv4 hardware has state to configure the virtual interrupt
injection, which we must model if the guest hypervisor should think it
runs on a GICv4 system and uses direct interrupt injection?

For example, the vPE table entries could be cached by the ITS and would
therefore need to be flushed if presenting a GICv4 to the guest.

To clarify:  I understand this comment to be about what we present to
the guest, a GICv3 or a GICv4, and doesn't affect whether or not we run
on a physical GICv3 or GICv4, so when Eric says 'physical LPIs' here, he
really means 'physical from the point of view of the VM', which are of
course virtual, but are physical in the virtual emulated GICv3.

I tried to clarify this in a fix I will send shortly.

> >>
> >>> +
> >>> + The device table and ITT are indexed by the deviceid and eventid,
> >>> + respectively. The collection table is not indexed by collectionid:
> >>> + CTEs are written in the table in the order of collection creation. All
> >>
> >> Is this order really relevant? Can we relax it? Would something break if
> >> collections were in a random order?
> > Christoffer asked me to mention the exact storage order or at least I
> > understood his comment that way. Nothing would break if we change the order.
> 
> OK. If that's not a requirement, then we should probably drop it.
> 
> Christoffer, what do you think?
> 
Yes, we should drop it.  I have a fix for this in my queue.

Thanks,
-Christoffer

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

* [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation
@ 2017-05-08 11:21           ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 11:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, May 08, 2017 at 10:14:21AM +0100, Marc Zyngier wrote:
> On 07/05/17 18:05, Auger Eric wrote:
> > Hi Marc,
> > 
> > On 07/05/2017 13:54, Marc Zyngier wrote:
> >> On Sat, May 06 2017 at  4:24:20 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> >>> Add description for how to access ITS registers and how to save/restore
> >>> ITS tables into/from memory.
> >>>
> >>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> >>>
> >>> ---
> >>> v6 -> v7:
> >>> - rephrase ordering sequence + few cosmetic changes
> >>>
> >>> v5 -> v6:
> >>> - add restoration ordering
> >>> - 256B -> 256 Byte aligned
> >>> - DTE Size is number of bits for the EVENTID
> >>> - s/GITS_READR/GITS_CREADR
> >>>
> >>> v4 -> v5:
> >>> - take into account Christoffer's comments
> >>> - pending table save on GICV3 side now
> >>>
> >>> v3 -> v4:
> >>> - take into account Peter's comments:
> >>>   - typos
> >>>   - KVM_DEV_ARM_VGIC_GRP_ITS_TABLES kvm_device_attr = 0
> >>>   - add a validity bit in DTE
> >>>   - document all fields in CTE and ITE
> >>>   - document ABI revision
> >>> - take into account Andre's comments:
> >>>   - document restrictions about GITS_CREADR writing and GITS_IIDR
> >>>   - document -EBUSY error if one or more VCPUS are runnning
> >>>   - document 64b registers only can be accessed with 64b access
> >>> - itt_addr field matches bits [51:8] of the itt_addr
> >>>
> >>> v1 -> v2:
> >>> - DTE and ITE now are 8 bytes
> >>> - DTE and ITE now indexed by deviceid/eventid
> >>> - use ITE name instead of ITTE
> >>> - mentions ITT_addr matches bits [51:8] of the actual address
> >>> - mentions LE layout
> >>> ---
> >>>  Documentation/virtual/kvm/devices/arm-vgic-its.txt | 120 +++++++++++++++++++++
> >>>  1 file changed, 120 insertions(+)
> >>>
> >>> diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> >>> index 6081a5b..ba132e9 100644
> >>> --- a/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> >>> +++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
> >> [...]
> >>
> >>> + ITS Table ABI REV0:
> >>> + -------------------
> >>> +
> >>> + Revision 0 of the ABI only supports physical LPIs.
> >>
> >> Nit: these are no more physical than any other interrupt that KVM deals
> >> with. If you're hinting at the lack of GICv4 support, it wouldn't
> >> necessarily invalidate this ABI. It is actually even likely that the ABI
> >> could stay the same (until we start supporting GICv4 in a nested
> >> configuration).
> > I understood vLPI are associated to vPE and not to collections. As such
> > ITE would need to be updated, wouldn't it?
> 
> Even in a GICv4 setup (and ignoring nesting), a guest would only see a
> normal GICv3, as all the GICv4 state is the hypervisor's business, and
> not something meaningful to the guest. Also, it is very desirable to be
> able to migrate a GICv4 setup to a GICv3 setup without breaking everything.
> 
> To precisely answer your question, the VPE setup is done by finding out
> which collection is mapped to which vcpu, and using that to map VLPIs to
> VPEs. None of that is observable by the guest.
> 

Doesn't GICv4 hardware has state to configure the virtual interrupt
injection, which we must model if the guest hypervisor should think it
runs on a GICv4 system and uses direct interrupt injection?

For example, the vPE table entries could be cached by the ITS and would
therefore need to be flushed if presenting a GICv4 to the guest.

To clarify:  I understand this comment to be about what we present to
the guest, a GICv3 or a GICv4, and doesn't affect whether or not we run
on a physical GICv3 or GICv4, so when Eric says 'physical LPIs' here, he
really means 'physical from the point of view of the VM', which are of
course virtual, but are physical in the virtual emulated GICv3.

I tried to clarify this in a fix I will send shortly.

> >>
> >>> +
> >>> + The device table and ITT are indexed by the deviceid and eventid,
> >>> + respectively. The collection table is not indexed by collectionid:
> >>> + CTEs are written in the table in the order of collection creation. All
> >>
> >> Is this order really relevant? Can we relax it? Would something break if
> >> collections were in a random order?
> > Christoffer asked me to mention the exact storage order or at least I
> > understood his comment that way. Nothing would break if we change the order.
> 
> OK. If that's not a requirement, then we should probably drop it.
> 
> Christoffer, what do you think?
> 
Yes, we should drop it.  I have a fix for this in my queue.

Thanks,
-Christoffer

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

* Re: [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
  2017-05-07 13:30     ` Marc Zyngier
@ 2017-05-08 11:30       ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 11:30 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Eric Auger, eric.auger.pro, christoffer.dall, andre.przywara,
	vijayak, Vijaya.Kumar, peter.maydell, linux-arm-kernel, kvmarm,
	kvm, Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela,
	bjsprakash.linux

On Sun, May 07, 2017 at 02:30:57PM +0100, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:40 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> > This patch saves the device table entries into guest RAM.
> > Both flat table and 2 stage tables are supported. DeviceId
> > indexing is used.
> >
> > For each device listed in the device table, we also save
> > the translation table using the vgic_its_save/restore_itt
> > routines. Those functions will be implemented in a subsequent
> > patch.
> >
> > On restore, devices are re-allocated and their itt are
> > re-built.
> >
> > Signed-off-by: Eric Auger <eric.auger@redhat.com>
> >
> > ---
> > v5 -> v6:
> > - accomodate vgic_its_alloc_device change of proto
> > - define bit fields for L1 entries
> > - s/handle_l1_entry/handle_l1_dte
> > - s/ite_esz/dte_esz in handle_l1_dte
> > - check BASER valid bit
> > - s/nb_eventid_bits/num_eventid_bits
> > - new convention for returned values
> > - itt functions implemented in subsequent patch
> >
> > v4 -> v5:
> > - sort the device list by deviceid on device table save
> > - use defines for shifts and masks
> > - use abi->dte_esz
> > - clatify entry sizes for L1 and L2 tables
> >
> > v3 -> v4:
> > - use the new proto for its_alloc_device
> > - compute_next_devid_offset, vgic_its_flush/restore_itt
> >   become static in this patch
> > - change in the DTE entry format with the introduction of the
> >   valid bit and next field width decrease; ittaddr encoded
> >   on its full range
> > - fix handle_l1_entry entry handling
> > - correct vgic_its_table_restore error handling
> >
> > v2 -> v3:
> > - fix itt_addr bitmask in vgic_its_restore_dte
> > - addition of return 0 in vgic_its_restore_ite moved to
> >   the ITE related patch
> >
> > v1 -> v2:
> > - use 8 byte format for DTE and ITE
> > - support 2 stage format
> > - remove kvm parameter
> > - ITT flush/restore moved in a separate patch
> > - use deviceid indexing
> > ---
> >  virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic.h     |  10 +++
> >  2 files changed, 199 insertions(+), 5 deletions(-)
> >
> > diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> > index 90afc83..3dea626 100644
> > --- a/virt/kvm/arm/vgic/vgic-its.c
> > +++ b/virt/kvm/arm/vgic/vgic-its.c
> > @@ -23,6 +23,7 @@
> >  #include <linux/interrupt.h>
> >  #include <linux/list.h>
> >  #include <linux/uaccess.h>
> > +#include <linux/list_sort.h>
> >  
> >  #include <linux/irqchip/arm-gic-v3.h>
> >  
> > @@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
> >  	return ret;
> >  }
> >  
> > -u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
> > +static u32 compute_next_devid_offset(struct list_head *h,
> > +				     struct its_device *dev)
> >  {
> >  	struct its_device *next;
> >  	u32 next_offset;
> > @@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
> >   * Return: < 0 on error, 0 if last element was identified, 1 otherwise
> >   * (the last element may not be found on second level tables)
> >   */
> > -int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> > -		   int start_id, entry_fn_t fn, void *opaque)
> > +static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> > +			  int start_id, entry_fn_t fn, void *opaque)
> >  {
> >  	void *entry = kzalloc(esz, GFP_KERNEL);
> >  	struct kvm *kvm = its->dev->kvm;
> > @@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> >  	return ret;
> >  }
> >  
> > +static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
> > +{
> > +	return -ENXIO;
> > +}
> > +
> > +static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
> > +{
> > +	return -ENXIO;
> > +}
> > +
> > +/**
> > + * vgic_its_save_dte - Save a device table entry at a given GPA
> > + *
> > + * @its: ITS handle
> > + * @dev: ITS device
> > + * @ptr: GPA
> > + */
> > +static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
> > +			     gpa_t ptr, int dte_esz)
> > +{
> > +	struct kvm *kvm = its->dev->kvm;
> > +	u64 val, itt_addr_field;
> > +	u32 next_offset;
> > +
> > +	itt_addr_field = dev->itt_addr >> 8;
> > +	next_offset = compute_next_devid_offset(&its->device_list, dev);
> > +	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
> > +	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
> > +	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
> > +		(dev->num_eventid_bits - 1));
> > +	val = cpu_to_le64(val);
> > +	return kvm_write_guest(kvm, ptr, &val, dte_esz);
> > +}
> > +
> > +/**
> > + * vgic_its_restore_dte - restore a device table entry
> > + *
> > + * @its: its handle
> > + * @id: device id the DTE corresponds to
> > + * @ptr: kernel VA where the 8 byte DTE is located
> > + * @opaque: unused
> > + *
> > + * Return: < 0 on error, 0 if the dte is the last one, id offset to the
> > + * next dte otherwise
> > + */
> > +static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
> > +				void *ptr, void *opaque)
> > +{
> > +	struct its_device *dev;
> > +	gpa_t itt_addr;
> > +	u8 num_eventid_bits;
> > +	u64 entry = *(u64 *)ptr;
> > +	bool valid;
> > +	u32 offset;
> > +	int ret;
> > +
> > +	entry = le64_to_cpu(entry);
> > +
> > +	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
> > +	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
> > +	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
> > +			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
> > +
> > +	if (!valid)
> > +		return 1;
> > +
> > +	/* dte entry is valid */
> > +	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
> > +
> > +	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
> > +	if (IS_ERR(dev))
> > +		return PTR_ERR(dev);
> > +
> > +	ret = vgic_its_restore_itt(its, dev);
> > +	if (ret)
> > +		return ret;
> 
> Shouldn't we free the device entry if the restore as failed?
> 

I don't think we need to in terms of a memleak.  If the device alloc
succeeded, the device will be on the its->device_list, which will get
traversed and each device will get freed when the device is closed.

In terms of correctness, we'll report an error and it's up to
userspace to figure out what to do, but I can think of two scenarios.
First, if it closes the VM and gives up, we're fine.  Second, if it
fixes up some data and attempts a restore again, then we'll end up with
double entries in the device list or partially restore data, which is
sort of bad.  So I guess it would be nicer to clean up after ourselves,
but not strictly required.

Thanks,
-Christoffer

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

* [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore
@ 2017-05-08 11:30       ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, May 07, 2017 at 02:30:57PM +0100, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:40 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> > This patch saves the device table entries into guest RAM.
> > Both flat table and 2 stage tables are supported. DeviceId
> > indexing is used.
> >
> > For each device listed in the device table, we also save
> > the translation table using the vgic_its_save/restore_itt
> > routines. Those functions will be implemented in a subsequent
> > patch.
> >
> > On restore, devices are re-allocated and their itt are
> > re-built.
> >
> > Signed-off-by: Eric Auger <eric.auger@redhat.com>
> >
> > ---
> > v5 -> v6:
> > - accomodate vgic_its_alloc_device change of proto
> > - define bit fields for L1 entries
> > - s/handle_l1_entry/handle_l1_dte
> > - s/ite_esz/dte_esz in handle_l1_dte
> > - check BASER valid bit
> > - s/nb_eventid_bits/num_eventid_bits
> > - new convention for returned values
> > - itt functions implemented in subsequent patch
> >
> > v4 -> v5:
> > - sort the device list by deviceid on device table save
> > - use defines for shifts and masks
> > - use abi->dte_esz
> > - clatify entry sizes for L1 and L2 tables
> >
> > v3 -> v4:
> > - use the new proto for its_alloc_device
> > - compute_next_devid_offset, vgic_its_flush/restore_itt
> >   become static in this patch
> > - change in the DTE entry format with the introduction of the
> >   valid bit and next field width decrease; ittaddr encoded
> >   on its full range
> > - fix handle_l1_entry entry handling
> > - correct vgic_its_table_restore error handling
> >
> > v2 -> v3:
> > - fix itt_addr bitmask in vgic_its_restore_dte
> > - addition of return 0 in vgic_its_restore_ite moved to
> >   the ITE related patch
> >
> > v1 -> v2:
> > - use 8 byte format for DTE and ITE
> > - support 2 stage format
> > - remove kvm parameter
> > - ITT flush/restore moved in a separate patch
> > - use deviceid indexing
> > ---
> >  virt/kvm/arm/vgic/vgic-its.c | 194 +++++++++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic.h     |  10 +++
> >  2 files changed, 199 insertions(+), 5 deletions(-)
> >
> > diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> > index 90afc83..3dea626 100644
> > --- a/virt/kvm/arm/vgic/vgic-its.c
> > +++ b/virt/kvm/arm/vgic/vgic-its.c
> > @@ -23,6 +23,7 @@
> >  #include <linux/interrupt.h>
> >  #include <linux/list.h>
> >  #include <linux/uaccess.h>
> > +#include <linux/list_sort.h>
> >  
> >  #include <linux/irqchip/arm-gic-v3.h>
> >  
> > @@ -1735,7 +1736,8 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
> >  	return ret;
> >  }
> >  
> > -u32 compute_next_devid_offset(struct list_head *h, struct its_device *dev)
> > +static u32 compute_next_devid_offset(struct list_head *h,
> > +				     struct its_device *dev)
> >  {
> >  	struct its_device *next;
> >  	u32 next_offset;
> > @@ -1789,8 +1791,8 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
> >   * Return: < 0 on error, 0 if last element was identified, 1 otherwise
> >   * (the last element may not be found on second level tables)
> >   */
> > -int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> > -		   int start_id, entry_fn_t fn, void *opaque)
> > +static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> > +			  int start_id, entry_fn_t fn, void *opaque)
> >  {
> >  	void *entry = kzalloc(esz, GFP_KERNEL);
> >  	struct kvm *kvm = its->dev->kvm;
> > @@ -1825,13 +1827,171 @@ int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> >  	return ret;
> >  }
> >  
> > +static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
> > +{
> > +	return -ENXIO;
> > +}
> > +
> > +static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
> > +{
> > +	return -ENXIO;
> > +}
> > +
> > +/**
> > + * vgic_its_save_dte - Save a device table entry at a given GPA
> > + *
> > + * @its: ITS handle
> > + * @dev: ITS device
> > + * @ptr: GPA
> > + */
> > +static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
> > +			     gpa_t ptr, int dte_esz)
> > +{
> > +	struct kvm *kvm = its->dev->kvm;
> > +	u64 val, itt_addr_field;
> > +	u32 next_offset;
> > +
> > +	itt_addr_field = dev->itt_addr >> 8;
> > +	next_offset = compute_next_devid_offset(&its->device_list, dev);
> > +	val = (1ULL << KVM_ITS_DTE_VALID_SHIFT |
> > +	       ((u64)next_offset << KVM_ITS_DTE_NEXT_SHIFT) |
> > +	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
> > +		(dev->num_eventid_bits - 1));
> > +	val = cpu_to_le64(val);
> > +	return kvm_write_guest(kvm, ptr, &val, dte_esz);
> > +}
> > +
> > +/**
> > + * vgic_its_restore_dte - restore a device table entry
> > + *
> > + * @its: its handle
> > + * @id: device id the DTE corresponds to
> > + * @ptr: kernel VA where the 8 byte DTE is located
> > + * @opaque: unused
> > + *
> > + * Return: < 0 on error, 0 if the dte is the last one, id offset to the
> > + * next dte otherwise
> > + */
> > +static int vgic_its_restore_dte(struct vgic_its *its, u32 id,
> > +				void *ptr, void *opaque)
> > +{
> > +	struct its_device *dev;
> > +	gpa_t itt_addr;
> > +	u8 num_eventid_bits;
> > +	u64 entry = *(u64 *)ptr;
> > +	bool valid;
> > +	u32 offset;
> > +	int ret;
> > +
> > +	entry = le64_to_cpu(entry);
> > +
> > +	valid = entry >> KVM_ITS_DTE_VALID_SHIFT;
> > +	num_eventid_bits = (entry & KVM_ITS_DTE_SIZE_MASK) + 1;
> > +	itt_addr = ((entry & KVM_ITS_DTE_ITTADDR_MASK)
> > +			>> KVM_ITS_DTE_ITTADDR_SHIFT) << 8;
> > +
> > +	if (!valid)
> > +		return 1;
> > +
> > +	/* dte entry is valid */
> > +	offset = (entry & KVM_ITS_DTE_NEXT_MASK) >> KVM_ITS_DTE_NEXT_SHIFT;
> > +
> > +	dev = vgic_its_alloc_device(its, id, itt_addr, num_eventid_bits);
> > +	if (IS_ERR(dev))
> > +		return PTR_ERR(dev);
> > +
> > +	ret = vgic_its_restore_itt(its, dev);
> > +	if (ret)
> > +		return ret;
> 
> Shouldn't we free the device entry if the restore as failed?
> 

I don't think we need to in terms of a memleak.  If the device alloc
succeeded, the device will be on the its->device_list, which will get
traversed and each device will get freed when the device is closed.

In terms of correctness, we'll report an error and it's up to
userspace to figure out what to do, but I can think of two scenarios.
First, if it closes the VM and gives up, we're fine.  Second, if it
fixes up some data and attempts a restore again, then we'll end up with
double entries in the device list or partially restore data, which is
sort of bad.  So I guess it would be nicer to clean up after ourselves,
but not strictly required.

Thanks,
-Christoffer

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

* Re: [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
  2017-05-07 13:39     ` Marc Zyngier
@ 2017-05-08 11:49       ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 11:49 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Eric Auger, eric.auger.pro, christoffer.dall, andre.przywara,
	vijayak, Vijaya.Kumar, peter.maydell, linux-arm-kernel, kvmarm,
	kvm, Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela,
	bjsprakash.linux

On Sun, May 07, 2017 at 02:39:33PM +0100, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:41 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> > Implement routines to save and restore device ITT and their
> > interrupt table entries (ITE).
> >
> > Signed-off-by: Eric Auger <eric.auger@redhat.com>
> > Reviewed-by: Christoffer Dall <cdall@linaro.org>
> >
> > ---
> > v6 -> v7:
> > - added Christoffer's R-b
> >
> > v5 -> v6:
> > - accomodate vgic_its_alloc_ite change of proto
> > - check LPI ID on restore, check eventid offset
> > - initializations on separate line
> > - coming after device save/restore
> > - add_lpi does config and pending bit sync
> >
> > v4 -> v5:
> > - ITE are now sorted by eventid on the flush
> > - rename *flush* into *save*
> > - use macros for shits and masks
> > - pass ite_esz to vgic_its_save_ite
> >
> > v3 -> v4:
> > - lookup_table and compute_next_eventid_offset become static in this
> >   patch
> > - remove static along with vgic_its_flush/restore_itt to avoid
> >   compilation warnings
> > - next field only computed with a shift (mask removed)
> > - handle the case where the last element has not been found
> >
> > v2 -> v3:
> > - add return 0 in vgic_its_restore_ite (was in subsequent patch)
> >
> > v2: creation
> > ---
> >  virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic.h     |   4 ++
> >  2 files changed, 117 insertions(+), 3 deletions(-)
> >
> > diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> > index 3dea626..adb3d9e 100644
> > --- a/virt/kvm/arm/vgic/vgic-its.c
> > +++ b/virt/kvm/arm/vgic/vgic-its.c
> > @@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
> >  	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
> >  }
> >  
> > -u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
> > +static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
> >  {
> >  	struct its_ite *next;
> >  	u32 next_offset;
> > @@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> >  	return ret;
> >  }
> >  
> > +/**
> > + * vgic_its_save_ite - Save an interrupt translation entry at @gpa
> > + */
> > +static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
> > +			      struct its_ite *ite, gpa_t gpa, int ite_esz)
> > +{
> > +	struct kvm *kvm = its->dev->kvm;
> > +	u32 next_offset;
> > +	u64 val;
> > +
> > +	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
> > +	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
> > +	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
> > +		ite->collection->collection_id;
> > +	val = cpu_to_le64(val);
> > +	return kvm_write_guest(kvm, gpa, &val, ite_esz);
> > +}
> > +
> > +/**
> > + * vgic_its_restore_ite - restore an interrupt translation entry
> > + * @event_id: id used for indexing
> > + * @ptr: pointer to the ITE entry
> > + * @opaque: pointer to the its_device
> > + */
> > +static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
> > +				void *ptr, void *opaque)
> > +{
> > +	struct its_device *dev = (struct its_device *)opaque;
> > +	struct its_collection *collection;
> > +	struct kvm *kvm = its->dev->kvm;
> > +	struct kvm_vcpu *vcpu = NULL;
> > +	u64 val;
> > +	u64 *p = (u64 *)ptr;
> > +	struct vgic_irq *irq;
> > +	u32 coll_id, lpi_id;
> > +	struct its_ite *ite;
> > +	u32 offset;
> > +
> > +	val = *p;
> > +
> > +	val = le64_to_cpu(val);
> > +
> > +	coll_id = val & KVM_ITS_ITE_ICID_MASK;
> > +	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
> > +
> > +	if (!lpi_id)
> > +		return 1; /* invalid entry, no choice but to scan next entry */
> > +
> > +	if (lpi_id < VGIC_MIN_LPI)
> > +		return -EINVAL;
> > +
> > +	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
> > +	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
> > +		return -EINVAL;
> > +
> > +	collection = find_collection(its, coll_id);
> > +	if (!collection)
> > +		return -EINVAL;
> > +
> > +	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
> > +	if (IS_ERR(ite))
> > +		return PTR_ERR(ite);
> > +
> > +	if (its_is_collection_mapped(collection))
> > +		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
> > +
> > +	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
> > +	if (IS_ERR(irq))
> > +		return PTR_ERR(irq);
> 
> Same remark as the previous patch: the its_ite structure should be freed
> on failure. Otherwise, I suspect we end0up leaking memory.
> 

This error would be propagated back to vgic_its_restore_dte() which
(folllowing our discussion on the previous patch) will clean up the
dte including freeing all ITEs associated with the device's ITT.

Thanks,
-Christoffer

> Thanks,
> 
> 	M.
> -- 
> Jazz is not dead, it just smell funny.

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

* [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore
@ 2017-05-08 11:49       ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 11:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, May 07, 2017 at 02:39:33PM +0100, Marc Zyngier wrote:
> On Sat, May 06 2017 at  4:24:41 pm BST, Eric Auger <eric.auger@redhat.com> wrote:
> > Implement routines to save and restore device ITT and their
> > interrupt table entries (ITE).
> >
> > Signed-off-by: Eric Auger <eric.auger@redhat.com>
> > Reviewed-by: Christoffer Dall <cdall@linaro.org>
> >
> > ---
> > v6 -> v7:
> > - added Christoffer's R-b
> >
> > v5 -> v6:
> > - accomodate vgic_its_alloc_ite change of proto
> > - check LPI ID on restore, check eventid offset
> > - initializations on separate line
> > - coming after device save/restore
> > - add_lpi does config and pending bit sync
> >
> > v4 -> v5:
> > - ITE are now sorted by eventid on the flush
> > - rename *flush* into *save*
> > - use macros for shits and masks
> > - pass ite_esz to vgic_its_save_ite
> >
> > v3 -> v4:
> > - lookup_table and compute_next_eventid_offset become static in this
> >   patch
> > - remove static along with vgic_its_flush/restore_itt to avoid
> >   compilation warnings
> > - next field only computed with a shift (mask removed)
> > - handle the case where the last element has not been found
> >
> > v2 -> v3:
> > - add return 0 in vgic_its_restore_ite (was in subsequent patch)
> >
> > v2: creation
> > ---
> >  virt/kvm/arm/vgic/vgic-its.c | 116 +++++++++++++++++++++++++++++++++++++++++--
> >  virt/kvm/arm/vgic/vgic.h     |   4 ++
> >  2 files changed, 117 insertions(+), 3 deletions(-)
> >
> > diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> > index 3dea626..adb3d9e 100644
> > --- a/virt/kvm/arm/vgic/vgic-its.c
> > +++ b/virt/kvm/arm/vgic/vgic-its.c
> > @@ -1750,7 +1750,7 @@ static u32 compute_next_devid_offset(struct list_head *h,
> >  	return min_t(u32, next_offset, VITS_DTE_MAX_DEVID_OFFSET);
> >  }
> >  
> > -u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
> > +static u32 compute_next_eventid_offset(struct list_head *h, struct its_ite *ite)
> >  {
> >  	struct its_ite *next;
> >  	u32 next_offset;
> > @@ -1827,14 +1827,124 @@ static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
> >  	return ret;
> >  }
> >  
> > +/**
> > + * vgic_its_save_ite - Save an interrupt translation entry at @gpa
> > + */
> > +static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
> > +			      struct its_ite *ite, gpa_t gpa, int ite_esz)
> > +{
> > +	struct kvm *kvm = its->dev->kvm;
> > +	u32 next_offset;
> > +	u64 val;
> > +
> > +	next_offset = compute_next_eventid_offset(&dev->itt_head, ite);
> > +	val = ((u64)next_offset << KVM_ITS_ITE_NEXT_SHIFT) |
> > +	       ((u64)ite->lpi << KVM_ITS_ITE_PINTID_SHIFT) |
> > +		ite->collection->collection_id;
> > +	val = cpu_to_le64(val);
> > +	return kvm_write_guest(kvm, gpa, &val, ite_esz);
> > +}
> > +
> > +/**
> > + * vgic_its_restore_ite - restore an interrupt translation entry
> > + * @event_id: id used for indexing
> > + * @ptr: pointer to the ITE entry
> > + * @opaque: pointer to the its_device
> > + */
> > +static int vgic_its_restore_ite(struct vgic_its *its, u32 event_id,
> > +				void *ptr, void *opaque)
> > +{
> > +	struct its_device *dev = (struct its_device *)opaque;
> > +	struct its_collection *collection;
> > +	struct kvm *kvm = its->dev->kvm;
> > +	struct kvm_vcpu *vcpu = NULL;
> > +	u64 val;
> > +	u64 *p = (u64 *)ptr;
> > +	struct vgic_irq *irq;
> > +	u32 coll_id, lpi_id;
> > +	struct its_ite *ite;
> > +	u32 offset;
> > +
> > +	val = *p;
> > +
> > +	val = le64_to_cpu(val);
> > +
> > +	coll_id = val & KVM_ITS_ITE_ICID_MASK;
> > +	lpi_id = (val & KVM_ITS_ITE_PINTID_MASK) >> KVM_ITS_ITE_PINTID_SHIFT;
> > +
> > +	if (!lpi_id)
> > +		return 1; /* invalid entry, no choice but to scan next entry */
> > +
> > +	if (lpi_id < VGIC_MIN_LPI)
> > +		return -EINVAL;
> > +
> > +	offset = val >> KVM_ITS_ITE_NEXT_SHIFT;
> > +	if (event_id + offset >= BIT_ULL(dev->num_eventid_bits))
> > +		return -EINVAL;
> > +
> > +	collection = find_collection(its, coll_id);
> > +	if (!collection)
> > +		return -EINVAL;
> > +
> > +	ite = vgic_its_alloc_ite(dev, collection, lpi_id, event_id);
> > +	if (IS_ERR(ite))
> > +		return PTR_ERR(ite);
> > +
> > +	if (its_is_collection_mapped(collection))
> > +		vcpu = kvm_get_vcpu(kvm, collection->target_addr);
> > +
> > +	irq = vgic_add_lpi(kvm, lpi_id, vcpu);
> > +	if (IS_ERR(irq))
> > +		return PTR_ERR(irq);
> 
> Same remark as the previous patch: the its_ite structure should be freed
> on failure. Otherwise, I suspect we end0up leaking memory.
> 

This error would be propagated back to vgic_its_restore_dte() which
(folllowing our discussion on the previous patch) will clean up the
dte including freeing all ITEs associated with the device's ITT.

Thanks,
-Christoffer

> Thanks,
> 
> 	M.
> -- 
> Jazz is not dead, it just smell funny.

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

* Re: [PATCH v7 09/24] KVM: arm64: vgic-its: Introduce migration ABI infrastructure
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-08 12:23     ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:23 UTC (permalink / raw)
  To: Eric Auger
  Cc: eric.auger.pro, marc.zyngier, christoffer.dall, andre.przywara,
	vijayak, Vijaya.Kumar, peter.maydell, linux-arm-kernel, kvmarm,
	kvm, Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela,
	bjsprakash.linux

On Sat, May 06, 2017 at 05:24:28PM +0200, Eric Auger wrote:
> We plan to support different migration ABIs, ie. characterizing
> the ITS table layout format in guest RAM. For example, a new ABI
> will be needed if vLPIs get supported for nested use case.
> 
> So let's introduce an array of supported ABIs (at the moment a single
> ABI is supported though). The following characteristics are foreseen
> to vary with the ABI: size of table entries, save/restore operation,
> the way abi settings are applied.
> 
> By default the MAX_ABI_REV is applied on its creation. In subsequent
> patches we will introduce a way for the userspace to change the ABI
> in use.
> 
> The entry sizes now are set according to the ABI version and not
> hardcoded anymore.
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> 
Reviewed-by: Christoffer Dall <cdall@linaro.org>

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

* [PATCH v7 09/24] KVM: arm64: vgic-its: Introduce migration ABI infrastructure
@ 2017-05-08 12:23     ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06, 2017 at 05:24:28PM +0200, Eric Auger wrote:
> We plan to support different migration ABIs, ie. characterizing
> the ITS table layout format in guest RAM. For example, a new ABI
> will be needed if vLPIs get supported for nested use case.
> 
> So let's introduce an array of supported ABIs (at the moment a single
> ABI is supported though). The following characteristics are foreseen
> to vary with the ABI: size of table entries, save/restore operation,
> the way abi settings are applied.
> 
> By default the MAX_ABI_REV is applied on its creation. In subsequent
> patches we will introduce a way for the userspace to change the ABI
> in use.
> 
> The entry sizes now are set according to the ABI version and not
> hardcoded anymore.
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> 
Reviewed-by: Christoffer Dall <cdall@linaro.org>

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

* Re: [PATCH v7 10/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_iidr
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-08 12:24     ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:24 UTC (permalink / raw)
  To: Eric Auger
  Cc: eric.auger.pro, marc.zyngier, christoffer.dall, andre.przywara,
	vijayak, Vijaya.Kumar, peter.maydell, linux-arm-kernel, kvmarm,
	kvm, Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela,
	bjsprakash.linux

On Sat, May 06, 2017 at 05:24:29PM +0200, Eric Auger wrote:
> The GITS_IIDR revision field is used to encode the migration ABI
> revision. So we need to restore it to check the table layout is
> readable by the destination.
> 
> By writing the IIDR, userspace thus forces the ABI revision to be
> used and this must be less than or equal to the max revision KVM
> supports.
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> 
> ---
> v6 -> v7:
> - use NR_ITS_ABIS
> - introduce & use GITS_IIDR_REV_MASK
> 
> v5 -> v6:
> - fix typos in the commit message
> - dont't use update_64bit_reg anymore
> 
> v4 -> v5
> - rename user_revision into abi_rev and REV into MAX_ABI_REV
> - IIDR reports abi_rev set by userspace if any.
> - If value set by userspace exceeds the max supported revision, an
>   error is reported.
> - add some defines
> 
> v4: creation
> ---
>  include/linux/irqchip/arm-gic-v3.h |  5 +++++
>  virt/kvm/arm/vgic/vgic-its.c       | 23 ++++++++++++++++++++---
>  2 files changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 81ebe43..2eaea30 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -242,6 +242,11 @@
>  #define GITS_TYPER_PTA			(1UL << 19)
>  #define GITS_TYPER_HWCOLLCNT_SHIFT	24
>  
> +#define GITS_IIDR_REV_SHIFT		12
> +#define GITS_IIDR_REV_MASK		(0xf << GITS_IIDR_REV_SHIFT)
> +#define GITS_IIDR_REV(r)		(((r) >> GITS_IIDR_REV_SHIFT) & 0xf)
> +#define GITS_IIDR_PRODUCTID_SHIFT	24
> +
>  #define GITS_CBASER_VALID			(1ULL << 63)
>  #define GITS_CBASER_SHAREABILITY_SHIFT		(10)
>  #define GITS_CBASER_INNER_CACHEABILITY_SHIFT	(59)
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index 4f6ea46..9338efb 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -434,7 +434,23 @@ static unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm,
>  					     struct vgic_its *its,
>  					     gpa_t addr, unsigned int len)
>  {
> -	return (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +	u32 val;
> +
> +	val = (its->abi_rev << GITS_IIDR_REV_SHIFT) & GITS_IIDR_REV_MASK;
> +	val |= (PRODUCT_ID_KVM << GITS_IIDR_PRODUCTID_SHIFT) | IMPLEMENTER_ARM;
> +	return val;
> +}
> +
> +static int vgic_mmio_uaccess_write_its_iidr(struct kvm *kvm,
> +					    struct vgic_its *its,
> +					    gpa_t addr, unsigned int len,
> +					    unsigned long val)
> +{
> +	u32 rev = GITS_IIDR_REV(val);
> +
> +	if (rev >= NR_ITS_ABIS)
> +		return -EINVAL;
> +	return vgic_its_set_abi(its, rev);
>  }
>  
>  static unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
> @@ -1415,8 +1431,9 @@ static struct vgic_register_region its_registers[] = {
>  	REGISTER_ITS_DESC(GITS_CTLR,
>  		vgic_mmio_read_its_ctlr, vgic_mmio_write_its_ctlr, 4,
>  		VGIC_ACCESS_32bit),
> -	REGISTER_ITS_DESC(GITS_IIDR,
> -		vgic_mmio_read_its_iidr, its_mmio_write_wi, 4,
> +	REGISTER_ITS_DESC_UACCESS(GITS_IIDR,
> +		vgic_mmio_read_its_iidr, its_mmio_write_wi,
> +		vgic_mmio_uaccess_write_its_iidr, 4,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_ITS_DESC(GITS_TYPER,
>  		vgic_mmio_read_its_typer, its_mmio_write_wi, 8,
> -- 
> 2.5.5
> 

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

* [PATCH v7 10/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_iidr
@ 2017-05-08 12:24     ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06, 2017 at 05:24:29PM +0200, Eric Auger wrote:
> The GITS_IIDR revision field is used to encode the migration ABI
> revision. So we need to restore it to check the table layout is
> readable by the destination.
> 
> By writing the IIDR, userspace thus forces the ABI revision to be
> used and this must be less than or equal to the max revision KVM
> supports.
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> 
> ---
> v6 -> v7:
> - use NR_ITS_ABIS
> - introduce & use GITS_IIDR_REV_MASK
> 
> v5 -> v6:
> - fix typos in the commit message
> - dont't use update_64bit_reg anymore
> 
> v4 -> v5
> - rename user_revision into abi_rev and REV into MAX_ABI_REV
> - IIDR reports abi_rev set by userspace if any.
> - If value set by userspace exceeds the max supported revision, an
>   error is reported.
> - add some defines
> 
> v4: creation
> ---
>  include/linux/irqchip/arm-gic-v3.h |  5 +++++
>  virt/kvm/arm/vgic/vgic-its.c       | 23 ++++++++++++++++++++---
>  2 files changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 81ebe43..2eaea30 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -242,6 +242,11 @@
>  #define GITS_TYPER_PTA			(1UL << 19)
>  #define GITS_TYPER_HWCOLLCNT_SHIFT	24
>  
> +#define GITS_IIDR_REV_SHIFT		12
> +#define GITS_IIDR_REV_MASK		(0xf << GITS_IIDR_REV_SHIFT)
> +#define GITS_IIDR_REV(r)		(((r) >> GITS_IIDR_REV_SHIFT) & 0xf)
> +#define GITS_IIDR_PRODUCTID_SHIFT	24
> +
>  #define GITS_CBASER_VALID			(1ULL << 63)
>  #define GITS_CBASER_SHAREABILITY_SHIFT		(10)
>  #define GITS_CBASER_INNER_CACHEABILITY_SHIFT	(59)
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index 4f6ea46..9338efb 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -434,7 +434,23 @@ static unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm,
>  					     struct vgic_its *its,
>  					     gpa_t addr, unsigned int len)
>  {
> -	return (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
> +	u32 val;
> +
> +	val = (its->abi_rev << GITS_IIDR_REV_SHIFT) & GITS_IIDR_REV_MASK;
> +	val |= (PRODUCT_ID_KVM << GITS_IIDR_PRODUCTID_SHIFT) | IMPLEMENTER_ARM;
> +	return val;
> +}
> +
> +static int vgic_mmio_uaccess_write_its_iidr(struct kvm *kvm,
> +					    struct vgic_its *its,
> +					    gpa_t addr, unsigned int len,
> +					    unsigned long val)
> +{
> +	u32 rev = GITS_IIDR_REV(val);
> +
> +	if (rev >= NR_ITS_ABIS)
> +		return -EINVAL;
> +	return vgic_its_set_abi(its, rev);
>  }
>  
>  static unsigned long vgic_mmio_read_its_idregs(struct kvm *kvm,
> @@ -1415,8 +1431,9 @@ static struct vgic_register_region its_registers[] = {
>  	REGISTER_ITS_DESC(GITS_CTLR,
>  		vgic_mmio_read_its_ctlr, vgic_mmio_write_its_ctlr, 4,
>  		VGIC_ACCESS_32bit),
> -	REGISTER_ITS_DESC(GITS_IIDR,
> -		vgic_mmio_read_its_iidr, its_mmio_write_wi, 4,
> +	REGISTER_ITS_DESC_UACCESS(GITS_IIDR,
> +		vgic_mmio_read_its_iidr, its_mmio_write_wi,
> +		vgic_mmio_uaccess_write_its_iidr, 4,
>  		VGIC_ACCESS_32bit),
>  	REGISTER_ITS_DESC(GITS_TYPER,
>  		vgic_mmio_read_its_typer, its_mmio_write_wi, 8,
> -- 
> 2.5.5
> 

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

* Re: [PATCH v7 14/24] KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-08 12:26     ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:26 UTC (permalink / raw)
  To: Eric Auger
  Cc: eric.auger.pro, marc.zyngier, christoffer.dall, andre.przywara,
	vijayak, Vijaya.Kumar, peter.maydell, linux-arm-kernel, kvmarm,
	kvm, Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela,
	bjsprakash.linux

On Sat, May 06, 2017 at 05:24:33PM +0200, Eric Auger wrote:
> this new helper synchronizes the irq pending_latch
> with the LPI pending bit status found in rdist pending table.
> As the status is consumed, we reset the bit in pending table.
> 
> As we need the PENDBASER_ADDRESS() in vgic-v3, let's move its
> definition in the irqchip header. We restore the full length
> of the field, ie [51:16]. Same for PROPBASER_ADDRESS with full
> field length of [51:12].
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> 

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
> 
> v6: new
> ---
>  include/linux/irqchip/arm-gic-v3.h |  2 ++
>  virt/kvm/arm/vgic/vgic-its.c       |  6 ++----
>  virt/kvm/arm/vgic/vgic-v3.c        | 44 ++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h           |  1 +
>  4 files changed, 49 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index be8bad0..fffb912 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -159,6 +159,8 @@
>  #define GICR_PROPBASER_RaWaWb	GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWb)
>  
>  #define GICR_PROPBASER_IDBITS_MASK			(0x1f)
> +#define GICR_PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 12))
> +#define GICR_PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 16))
>  
>  #define GICR_PENDBASER_SHAREABILITY_SHIFT		(10)
>  #define GICR_PENDBASER_INNER_CACHEABILITY_SHIFT		(7)
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index bd1362e..3601790 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -221,8 +221,6 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
>   */
>  #define BASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
>  #define CBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
> -#define PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
> -#define PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
>  
>  #define GIC_LPI_OFFSET 8192
>  
> @@ -257,7 +255,7 @@ static struct its_collection *find_collection(struct vgic_its *its, int coll_id)
>  static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
>  			     struct kvm_vcpu *filter_vcpu)
>  {
> -	u64 propbase = PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
> +	u64 propbase = GICR_PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
>  	u8 prop;
>  	int ret;
>  
> @@ -369,7 +367,7 @@ static u32 max_lpis_propbaser(u64 propbaser)
>   */
>  static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
>  {
> -	gpa_t pendbase = PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
> +	gpa_t pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
>  	struct vgic_irq *irq;
>  	int last_byte_offset = -1;
>  	int ret = 0;
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index be0f4c3..0d753ae 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -252,6 +252,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
>  
> +int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int byte_offset, bit_nr;
> +	gpa_t pendbase, ptr;
> +	bool status;
> +	u8 val;
> +	int ret;
> +
> +retry:
> +	vcpu = irq->target_vcpu;
> +	if (!vcpu)
> +		return 0;
> +
> +	pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
> +
> +	byte_offset = irq->intid / BITS_PER_BYTE;
> +	bit_nr = irq->intid % BITS_PER_BYTE;
> +	ptr = pendbase + byte_offset;
> +
> +	ret = kvm_read_guest(kvm, ptr, &val, 1);
> +	if (ret)
> +		return ret;
> +
> +	status = val & (1 << bit_nr);
> +
> +	spin_lock(&irq->irq_lock);
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		goto retry;
> +	}
> +	irq->pending_latch = status;
> +	vgic_queue_irq_unlock(vcpu->kvm, irq);
> +
> +	if (status) {
> +		/* clear consumed data */
> +		val &= ~(1 << bit_nr);
> +		ret = kvm_write_guest(kvm, ptr, &val, 1);
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
>  /* check for overlapping regions and for regions crossing the end of memory */
>  static bool vgic_v3_check_base(struct kvm *kvm)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index b87f1c6..309ab64 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -157,6 +157,7 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(const struct gic_kvm_info *info);
>  int vgic_v3_map_resources(struct kvm *kvm);
> +int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  
>  int vgic_register_its_iodevs(struct kvm *kvm);
> -- 
> 2.5.5
> 

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

* [PATCH v7 14/24] KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status
@ 2017-05-08 12:26     ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06, 2017 at 05:24:33PM +0200, Eric Auger wrote:
> this new helper synchronizes the irq pending_latch
> with the LPI pending bit status found in rdist pending table.
> As the status is consumed, we reset the bit in pending table.
> 
> As we need the PENDBASER_ADDRESS() in vgic-v3, let's move its
> definition in the irqchip header. We restore the full length
> of the field, ie [51:16]. Same for PROPBASER_ADDRESS with full
> field length of [51:12].
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> 

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
> 
> v6: new
> ---
>  include/linux/irqchip/arm-gic-v3.h |  2 ++
>  virt/kvm/arm/vgic/vgic-its.c       |  6 ++----
>  virt/kvm/arm/vgic/vgic-v3.c        | 44 ++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h           |  1 +
>  4 files changed, 49 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index be8bad0..fffb912 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -159,6 +159,8 @@
>  #define GICR_PROPBASER_RaWaWb	GIC_BASER_CACHEABILITY(GICR_PROPBASER, INNER, RaWaWb)
>  
>  #define GICR_PROPBASER_IDBITS_MASK			(0x1f)
> +#define GICR_PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 12))
> +#define GICR_PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(51, 16))
>  
>  #define GICR_PENDBASER_SHAREABILITY_SHIFT		(10)
>  #define GICR_PENDBASER_INNER_CACHEABILITY_SHIFT		(7)
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index bd1362e..3601790 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -221,8 +221,6 @@ static struct its_ite *find_ite(struct vgic_its *its, u32 device_id,
>   */
>  #define BASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
>  #define CBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
> -#define PENDBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 16))
> -#define PROPBASER_ADDRESS(x)	((x) & GENMASK_ULL(47, 12))
>  
>  #define GIC_LPI_OFFSET 8192
>  
> @@ -257,7 +255,7 @@ static struct its_collection *find_collection(struct vgic_its *its, int coll_id)
>  static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq,
>  			     struct kvm_vcpu *filter_vcpu)
>  {
> -	u64 propbase = PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
> +	u64 propbase = GICR_PROPBASER_ADDRESS(kvm->arch.vgic.propbaser);
>  	u8 prop;
>  	int ret;
>  
> @@ -369,7 +367,7 @@ static u32 max_lpis_propbaser(u64 propbaser)
>   */
>  static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
>  {
> -	gpa_t pendbase = PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
> +	gpa_t pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
>  	struct vgic_irq *irq;
>  	int last_byte_offset = -1;
>  	int ret = 0;
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index be0f4c3..0d753ae 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -252,6 +252,50 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
>  }
>  
> +int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
> +{
> +	struct kvm_vcpu *vcpu;
> +	int byte_offset, bit_nr;
> +	gpa_t pendbase, ptr;
> +	bool status;
> +	u8 val;
> +	int ret;
> +
> +retry:
> +	vcpu = irq->target_vcpu;
> +	if (!vcpu)
> +		return 0;
> +
> +	pendbase = GICR_PENDBASER_ADDRESS(vcpu->arch.vgic_cpu.pendbaser);
> +
> +	byte_offset = irq->intid / BITS_PER_BYTE;
> +	bit_nr = irq->intid % BITS_PER_BYTE;
> +	ptr = pendbase + byte_offset;
> +
> +	ret = kvm_read_guest(kvm, ptr, &val, 1);
> +	if (ret)
> +		return ret;
> +
> +	status = val & (1 << bit_nr);
> +
> +	spin_lock(&irq->irq_lock);
> +	if (irq->target_vcpu != vcpu) {
> +		spin_unlock(&irq->irq_lock);
> +		goto retry;
> +	}
> +	irq->pending_latch = status;
> +	vgic_queue_irq_unlock(vcpu->kvm, irq);
> +
> +	if (status) {
> +		/* clear consumed data */
> +		val &= ~(1 << bit_nr);
> +		ret = kvm_write_guest(kvm, ptr, &val, 1);
> +		if (ret)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
>  /* check for overlapping regions and for regions crossing the end of memory */
>  static bool vgic_v3_check_base(struct kvm *kvm)
>  {
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index b87f1c6..309ab64 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -157,6 +157,7 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
>  void vgic_v3_enable(struct kvm_vcpu *vcpu);
>  int vgic_v3_probe(const struct gic_kvm_info *info);
>  int vgic_v3_map_resources(struct kvm *kvm);
> +int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
>  int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
>  
>  int vgic_register_its_iodevs(struct kvm *kvm);
> -- 
> 2.5.5
> 

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

* Re: [PATCH v7 15/24] KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-08 12:28     ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:28 UTC (permalink / raw)
  To: Eric Auger
  Cc: eric.auger.pro, marc.zyngier, christoffer.dall, andre.przywara,
	vijayak, Vijaya.Kumar, peter.maydell, linux-arm-kernel, kvmarm,
	kvm, Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela,
	bjsprakash.linux

On Sat, May 06, 2017 at 05:24:34PM +0200, Eric Auger wrote:
> When creating the lpi we now ask the redistributor what is the state
> of the LPI (priority, enabled, pending).
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> 

Reviewed-by: Christoffer Dall <cdall@linaro.org>

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

* [PATCH v7 15/24] KVM: arm64: vgic-its: Read config and pending bit in add_lpi()
@ 2017-05-08 12:28     ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06, 2017 at 05:24:34PM +0200, Eric Auger wrote:
> When creating the lpi we now ask the redistributor what is the state
> of the LPI (priority, enabled, pending).
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
> 

Reviewed-by: Christoffer Dall <cdall@linaro.org>

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

* Re: [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
  2017-05-06 15:24   ` Eric Auger
@ 2017-05-08 12:29     ` Christoffer Dall
  -1 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:29 UTC (permalink / raw)
  To: Eric Auger
  Cc: eric.auger.pro, marc.zyngier, christoffer.dall, andre.przywara,
	vijayak, Vijaya.Kumar, peter.maydell, linux-arm-kernel, kvmarm,
	kvm, Prasun.Kapoor, drjones, pbonzini, dgilbert, quintela,
	bjsprakash.linux

On Sat, May 06, 2017 at 05:24:35PM +0200, Eric Auger wrote:
> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>   structures.
> 
> We hold the vcpus lock during the save and restore to make
> sure no vcpu is running.
> 
> At this stage the functionality is not yet implemented. Only
> the skeleton is put in place.
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

[with the expectation that the map_resources thing is fixed later]

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> 
> ---
> v6 -> v7:
> - also hold the its_lock on save and restore
> 
> v5 -> v6:
> - remove the pending table sync from the ITS table restore
> 
> v4 -> v5:
> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
> - rename *flush* into *save*
> - call its_sync_lpi_pending_table at the end of restore
> - use abi framework
> 
> v3 -> v4:
> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
> - take the kvm lock and vcpu locks
> - ABI revision check
> - check attr->attr is null
> 
> v1 -> v2:
> - remove useless kvm parameter
> ---
>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>  3 files changed, 109 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index 4beb83b..8e6563c 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -199,7 +199,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
>  #define VGIC_LEVEL_INFO_LINE_LEVEL	0
>  
> -#define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
> +#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
> +#define   KVM_DEV_ARM_ITS_SAVE_TABLES		1
> +#define   KVM_DEV_ARM_ITS_RESTORE_TABLES	2
>  
>  /* KVM_IRQ_LINE irq field index values */
>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 7e8dd69..1e35115 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -219,7 +219,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
>  #define VGIC_LEVEL_INFO_LINE_LEVEL	0
>  
> -#define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
> +#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
> +#define   KVM_DEV_ARM_ITS_SAVE_TABLES           1
> +#define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
>  
>  /* Device Control API on vcpu fd */
>  #define KVM_ARM_VCPU_PMU_V3_CTRL	0
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index ffd0a80..cb7ae4c 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -1703,12 +1703,71 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
>  }
>  
>  /**
> + * vgic_its_save_device_tables - Save the device table and all ITT
> + * into guest RAM
> + */
> +static int vgic_its_save_device_tables(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_restore_device_tables - Restore the device table and all ITT
> + * from guest RAM to internal data structs
> + */
> +static int vgic_its_restore_device_tables(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_save_collection_table - Save the collection table into
> + * guest RAM
> + */
> +static int vgic_its_save_collection_table(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_restore_collection_table - reads the collection table
> + * in guest memory and restores the ITS internal state. Requires the
> + * BASER registers to be restored before.
> + */
> +static int vgic_its_restore_collection_table(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
>   * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
>   * according to v0 ABI
>   */
>  static int vgic_its_save_tables_v0(struct vgic_its *its)
>  {
> -	return -ENXIO;
> +	struct kvm *kvm = its->dev->kvm;
> +	int ret;
> +
> +	mutex_lock(&kvm->lock);
> +	mutex_lock(&its->its_lock);
> +
> +	if (!lock_all_vcpus(kvm)) {
> +		mutex_unlock(&its->its_lock);
> +		mutex_unlock(&kvm->lock);
> +		return -EBUSY;
> +	}
> +
> +	ret = vgic_its_save_device_tables(its);
> +	if (ret)
> +		goto out;
> +
> +	ret = vgic_its_save_collection_table(its);
> +
> +out:
> +	unlock_all_vcpus(kvm);
> +	mutex_unlock(&its->its_lock);
> +	mutex_unlock(&kvm->lock);
> +	return ret;
>  }
>  
>  /**
> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>   */
>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>  {
> -	return -ENXIO;
> +	struct kvm *kvm = its->dev->kvm;
> +	int ret;
> +
> +	mutex_lock(&kvm->lock);
> +	mutex_lock(&its->its_lock);
> +
> +	if (!lock_all_vcpus(kvm)) {
> +		mutex_unlock(&its->its_lock);
> +		mutex_unlock(&kvm->lock);
> +		return -EBUSY;
> +	}
> +
> +	ret = vgic_its_restore_collection_table(its);
> +	if (ret)
> +		goto out;
> +
> +	ret = vgic_its_restore_device_tables(its);
> +
> +out:
> +	unlock_all_vcpus(kvm);
> +	mutex_unlock(&its->its_lock);
> +	mutex_unlock(&kvm->lock);
> +
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * On restore path, MSI injections can happen before the
> +	 * first VCPU run so let's complete the GIC init here.
> +	 */
> +	return kvm_vgic_map_resources(its->dev->kvm);
>  }
>  
>  static int vgic_its_commit_v0(struct vgic_its *its)
> @@ -1751,6 +1840,10 @@ static int vgic_its_has_attr(struct kvm_device *dev,
>  		switch (attr->attr) {
>  		case KVM_DEV_ARM_VGIC_CTRL_INIT:
>  			return 0;
> +		case KVM_DEV_ARM_ITS_SAVE_TABLES:
> +			return 0;
> +		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
> +			return 0;
>  		}
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
> @@ -1786,14 +1879,20 @@ static int vgic_its_set_attr(struct kvm_device *dev,
>  
>  		return 0;
>  	}
> -	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
> +		const struct vgic_its_abi *abi = vgic_its_get_abi(its);
> +
>  		switch (attr->attr) {
>  		case KVM_DEV_ARM_VGIC_CTRL_INIT:
>  			its->initialized = true;
>  
>  			return 0;
> +		case KVM_DEV_ARM_ITS_SAVE_TABLES:
> +			return abi->save_tables(its);
> +		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
> +			return abi->restore_tables(its);
>  		}
> -		break;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
>  		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
>  		u64 reg;
> -- 
> 2.5.5
> 

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

* [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES
@ 2017-05-08 12:29     ` Christoffer Dall
  0 siblings, 0 replies; 110+ messages in thread
From: Christoffer Dall @ 2017-05-08 12:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, May 06, 2017 at 05:24:35PM +0200, Eric Auger wrote:
> Introduce new attributes in KVM_DEV_ARM_VGIC_GRP_CTRL group:
> - KVM_DEV_ARM_ITS_SAVE_TABLES: saves the ITS tables into guest RAM
> - KVM_DEV_ARM_ITS_RESTORE_TABLES: restores them into VGIC internal
>   structures.
> 
> We hold the vcpus lock during the save and restore to make
> sure no vcpu is running.
> 
> At this stage the functionality is not yet implemented. Only
> the skeleton is put in place.
> 
> Signed-off-by: Eric Auger <eric.auger@redhat.com>

[with the expectation that the map_resources thing is fixed later]

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> 
> ---
> v6 -> v7:
> - also hold the its_lock on save and restore
> 
> v5 -> v6:
> - remove the pending table sync from the ITS table restore
> 
> v4 -> v5:
> - use KVM_DEV_ARM_ITS_SAVE_TABLES and KVM_DEV_ARM_ITS_RESTORE_TABLES
> - rename *flush* into *save*
> - call its_sync_lpi_pending_table at the end of restore
> - use abi framework
> 
> v3 -> v4:
> - pass kvm struct handle to vgic_its_flush/restore_pending_tables
> - take the kvm lock and vcpu locks
> - ABI revision check
> - check attr->attr is null
> 
> v1 -> v2:
> - remove useless kvm parameter
> ---
>  arch/arm/include/uapi/asm/kvm.h   |   4 +-
>  arch/arm64/include/uapi/asm/kvm.h |   4 +-
>  virt/kvm/arm/vgic/vgic-its.c      | 107 ++++++++++++++++++++++++++++++++++++--
>  3 files changed, 109 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
> index 4beb83b..8e6563c 100644
> --- a/arch/arm/include/uapi/asm/kvm.h
> +++ b/arch/arm/include/uapi/asm/kvm.h
> @@ -199,7 +199,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK 0x3ff
>  #define VGIC_LEVEL_INFO_LINE_LEVEL	0
>  
> -#define   KVM_DEV_ARM_VGIC_CTRL_INIT    0
> +#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
> +#define   KVM_DEV_ARM_ITS_SAVE_TABLES		1
> +#define   KVM_DEV_ARM_ITS_RESTORE_TABLES	2
>  
>  /* KVM_IRQ_LINE irq field index values */
>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 7e8dd69..1e35115 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -219,7 +219,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK	0x3ff
>  #define VGIC_LEVEL_INFO_LINE_LEVEL	0
>  
> -#define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
> +#define   KVM_DEV_ARM_VGIC_CTRL_INIT		0
> +#define   KVM_DEV_ARM_ITS_SAVE_TABLES           1
> +#define   KVM_DEV_ARM_ITS_RESTORE_TABLES        2
>  
>  /* Device Control API on vcpu fd */
>  #define KVM_ARM_VCPU_PMU_V3_CTRL	0
> diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
> index ffd0a80..cb7ae4c 100644
> --- a/virt/kvm/arm/vgic/vgic-its.c
> +++ b/virt/kvm/arm/vgic/vgic-its.c
> @@ -1703,12 +1703,71 @@ int vgic_its_attr_regs_access(struct kvm_device *dev,
>  }
>  
>  /**
> + * vgic_its_save_device_tables - Save the device table and all ITT
> + * into guest RAM
> + */
> +static int vgic_its_save_device_tables(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_restore_device_tables - Restore the device table and all ITT
> + * from guest RAM to internal data structs
> + */
> +static int vgic_its_restore_device_tables(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_save_collection_table - Save the collection table into
> + * guest RAM
> + */
> +static int vgic_its_save_collection_table(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
> + * vgic_its_restore_collection_table - reads the collection table
> + * in guest memory and restores the ITS internal state. Requires the
> + * BASER registers to be restored before.
> + */
> +static int vgic_its_restore_collection_table(struct vgic_its *its)
> +{
> +	return -ENXIO;
> +}
> +
> +/**
>   * vgic_its_save_tables_v0 - Save the ITS tables into guest ARM
>   * according to v0 ABI
>   */
>  static int vgic_its_save_tables_v0(struct vgic_its *its)
>  {
> -	return -ENXIO;
> +	struct kvm *kvm = its->dev->kvm;
> +	int ret;
> +
> +	mutex_lock(&kvm->lock);
> +	mutex_lock(&its->its_lock);
> +
> +	if (!lock_all_vcpus(kvm)) {
> +		mutex_unlock(&its->its_lock);
> +		mutex_unlock(&kvm->lock);
> +		return -EBUSY;
> +	}
> +
> +	ret = vgic_its_save_device_tables(its);
> +	if (ret)
> +		goto out;
> +
> +	ret = vgic_its_save_collection_table(its);
> +
> +out:
> +	unlock_all_vcpus(kvm);
> +	mutex_unlock(&its->its_lock);
> +	mutex_unlock(&kvm->lock);
> +	return ret;
>  }
>  
>  /**
> @@ -1718,7 +1777,37 @@ static int vgic_its_save_tables_v0(struct vgic_its *its)
>   */
>  static int vgic_its_restore_tables_v0(struct vgic_its *its)
>  {
> -	return -ENXIO;
> +	struct kvm *kvm = its->dev->kvm;
> +	int ret;
> +
> +	mutex_lock(&kvm->lock);
> +	mutex_lock(&its->its_lock);
> +
> +	if (!lock_all_vcpus(kvm)) {
> +		mutex_unlock(&its->its_lock);
> +		mutex_unlock(&kvm->lock);
> +		return -EBUSY;
> +	}
> +
> +	ret = vgic_its_restore_collection_table(its);
> +	if (ret)
> +		goto out;
> +
> +	ret = vgic_its_restore_device_tables(its);
> +
> +out:
> +	unlock_all_vcpus(kvm);
> +	mutex_unlock(&its->its_lock);
> +	mutex_unlock(&kvm->lock);
> +
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * On restore path, MSI injections can happen before the
> +	 * first VCPU run so let's complete the GIC init here.
> +	 */
> +	return kvm_vgic_map_resources(its->dev->kvm);
>  }
>  
>  static int vgic_its_commit_v0(struct vgic_its *its)
> @@ -1751,6 +1840,10 @@ static int vgic_its_has_attr(struct kvm_device *dev,
>  		switch (attr->attr) {
>  		case KVM_DEV_ARM_VGIC_CTRL_INIT:
>  			return 0;
> +		case KVM_DEV_ARM_ITS_SAVE_TABLES:
> +			return 0;
> +		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
> +			return 0;
>  		}
>  		break;
>  	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS:
> @@ -1786,14 +1879,20 @@ static int vgic_its_set_attr(struct kvm_device *dev,
>  
>  		return 0;
>  	}
> -	case KVM_DEV_ARM_VGIC_GRP_CTRL:
> +	case KVM_DEV_ARM_VGIC_GRP_CTRL: {
> +		const struct vgic_its_abi *abi = vgic_its_get_abi(its);
> +
>  		switch (attr->attr) {
>  		case KVM_DEV_ARM_VGIC_CTRL_INIT:
>  			its->initialized = true;
>  
>  			return 0;
> +		case KVM_DEV_ARM_ITS_SAVE_TABLES:
> +			return abi->save_tables(its);
> +		case KVM_DEV_ARM_ITS_RESTORE_TABLES:
> +			return abi->restore_tables(its);
>  		}
> -		break;
> +	}
>  	case KVM_DEV_ARM_VGIC_GRP_ITS_REGS: {
>  		u64 __user *uaddr = (u64 __user *)(long)attr->addr;
>  		u64 reg;
> -- 
> 2.5.5
> 

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

end of thread, other threads:[~2017-05-08 12:29 UTC | newest]

Thread overview: 110+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-06 15:24 [PATCH v7 00/24] vITS save/restore Eric Auger
2017-05-06 15:24 ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 01/24] KVM: arm/arm64: Add ITS save/restore API documentation Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 11:54   ` Marc Zyngier
2017-05-07 11:54     ` Marc Zyngier
2017-05-07 17:05     ` Auger Eric
2017-05-07 17:05       ` Auger Eric
2017-05-08  9:14       ` Marc Zyngier
2017-05-08  9:14         ` Marc Zyngier
2017-05-08 11:21         ` Christoffer Dall
2017-05-08 11:21           ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 02/24] KVM: arm/arm64: Add GICV3 pending table save " Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 11:56   ` Marc Zyngier
2017-05-07 11:56     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 03/24] KVM: arm/arm64: vgic-its: rename itte into ite Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 04/24] arm/arm64: vgic: turn vgic_find_mmio_region into public Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 05/24] KVM: arm64: vgic-its: KVM_DEV_ARM_VGIC_GRP_ITS_REGS group Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 06/24] KVM: arm/arm64: vgic: expose (un)lock_all_vcpus Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 07/24] KVM: arm64: vgic-its: Implement vgic_its_has_attr_regs and attr_regs_access Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 11:57   ` Marc Zyngier
2017-05-07 11:57     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 08/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_creadr Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 09/24] KVM: arm64: vgic-its: Introduce migration ABI infrastructure Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-08 12:23   ` Christoffer Dall
2017-05-08 12:23     ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 10/24] KVM: arm64: vgic-its: Implement vgic_mmio_uaccess_write_its_iidr Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-08 12:24   ` Christoffer Dall
2017-05-08 12:24     ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 11/24] KVM: arm64: vgic-its: Interpret MAPD Size field and check related errors Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 12/24] KVM: arm64: vgic-its: Interpret MAPD ITT_addr field Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-06 15:24 ` [PATCH v7 13/24] KVM: arm64: vgic-its: Check the device id matches TYPER DEVBITS range Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 12:01   ` Marc Zyngier
2017-05-07 12:01     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 14/24] KVM: arm64: vgic-v3: vgic_v3_lpi_sync_pending_status Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 12:13   ` Marc Zyngier
2017-05-07 12:13     ` Marc Zyngier
2017-05-08 12:26   ` Christoffer Dall
2017-05-08 12:26     ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 15/24] KVM: arm64: vgic-its: Read config and pending bit in add_lpi() Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 12:16   ` Marc Zyngier
2017-05-07 12:16     ` Marc Zyngier
2017-05-08 12:28   ` Christoffer Dall
2017-05-08 12:28     ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 16/24] KVM: arm64: vgic-its: KVM_DEV_ARM_ITS_SAVE/RESTORE_TABLES Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:00   ` Marc Zyngier
2017-05-07 13:00     ` Marc Zyngier
2017-05-07 13:51     ` Marc Zyngier
2017-05-07 13:51       ` Marc Zyngier
2017-05-07 15:19       ` Christoffer Dall
2017-05-07 15:19         ` Christoffer Dall
2017-05-07 17:33       ` Auger Eric
2017-05-07 17:33         ` Auger Eric
2017-05-08 12:29   ` Christoffer Dall
2017-05-08 12:29     ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 17/24] KVM: arm64: vgic-its: vgic_its_alloc_ite/device Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:02   ` Marc Zyngier
2017-05-07 13:02     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 18/24] KVM: arm64: vgic-its: Add infrastructure for table lookup Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:05   ` Marc Zyngier
2017-05-07 13:05     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 19/24] KVM: arm64: vgic-its: Collection table save/restore Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:12   ` Marc Zyngier
2017-05-07 13:12     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 20/24] KVM: arm64: vgic-its: vgic_its_check_id returns the entry's GPA Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:14   ` Marc Zyngier
2017-05-07 13:14     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 21/24] KVM: arm64: vgic-its: Device table save/restore Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:30   ` Marc Zyngier
2017-05-07 13:30     ` Marc Zyngier
2017-05-07 17:22     ` Auger Eric
2017-05-07 17:22       ` Auger Eric
2017-05-08 11:30     ` Christoffer Dall
2017-05-08 11:30       ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 22/24] KVM: arm64: vgic-its: ITT save and restore Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:39   ` Marc Zyngier
2017-05-07 13:39     ` Marc Zyngier
2017-05-07 17:24     ` Auger Eric
2017-05-07 17:24       ` Auger Eric
2017-05-08 11:49     ` Christoffer Dall
2017-05-08 11:49       ` Christoffer Dall
2017-05-06 15:24 ` [PATCH v7 23/24] KVM: arm64: vgic-its: Fix pending table sync Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:42   ` Marc Zyngier
2017-05-07 13:42     ` Marc Zyngier
2017-05-06 15:24 ` [PATCH v7 24/24] KVM: arm64: vgic-v3: KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES Eric Auger
2017-05-06 15:24   ` Eric Auger
2017-05-07 13:44   ` Marc Zyngier
2017-05-07 13:44     ` Marc Zyngier

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.