All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/19] KVM: ARM64: Add guest PMU support
@ 2015-12-15  8:49 ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

This patchset adds guest PMU support for KVM on ARM64. It takes
trap-and-emulate approach. When guest wants to monitor one event, it
will be trapped by KVM and KVM will call perf_event API to create a perf
event and call relevant perf_event APIs to get the count value of event.

Use perf to test this patchset in guest. When using "perf list", it
shows the list of the hardware events and hardware cache events perf
supports. Then use "perf stat -e EVENT" to monitor some event. For
example, use "perf stat -e cycles" to count cpu cycles and
"perf stat -e cache-misses" to count cache misses.

Below are the outputs of "perf stat -r 5 sleep 5" when running in host
and guest.

Host:
 Performance counter stats for 'sleep 5' (5 runs):

          0.549456      task-clock (msec)         #    0.000 CPUs utilized            ( +-  5.68% )
                 1      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
                48      page-faults               #    0.088 M/sec                    ( +-  1.40% )
           1146243      cycles                    #    2.086 GHz                      ( +-  5.71% )
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
            627195      instructions              #    0.55  insns per cycle          ( +- 15.65% )
   <not supported>      branches
              9826      branch-misses             #   17.883 M/sec                    ( +-  1.10% )

       5.000875516 seconds time elapsed                                          ( +-  0.00% )


Guest:
 Performance counter stats for 'sleep 5' (5 runs):

          0.640712      task-clock (msec)         #    0.000 CPUs utilized            ( +-  0.41% )
                 1      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
                50      page-faults               #    0.077 M/sec                    ( +-  1.37% )
           1320428      cycles                    #    2.061 GHz                      ( +-  0.29% )
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
            642373      instructions              #    0.49  insns per cycle          ( +-  0.46% )
   <not supported>      branches
             10399      branch-misses             #   16.230 M/sec                    ( +-  1.57% )

       5.001181020 seconds time elapsed                                          ( +-  0.00% )


Have a cycle counter read test like below in guest and host:

static void test(void)
{
	unsigned long count, count1, count2;
	count1 = read_cycles();
	count++;
	count2 = read_cycles();
}

Host:
count1: 3049567104
count2: 3049567247
delta: 143

Guest:
count1: 5281420890
count2: 5281421068
delta: 178

The gap between guest and host is very small. One reason for this I
think is that it doesn't count the cycles in EL2 and host since we add
exclude_hv = 1. So the cycles spent to store/restore registers which
happens at EL2 are not included.

This patchset can be fetched from [1] and the relevant QEMU version for
test can be fetched from [2].

The results of 'perf test' can be found from [3][4].
The results of perf_event_tests test suite can be found from [5][6].

Also, I have tested "perf top" in two VMs and host at the same time. It
works well.

Thanks,
Shannon

[1] https://git.linaro.org/people/shannon.zhao/linux-mainline.git  KVM_ARM64_PMU_v7
[2] https://git.linaro.org/people/shannon.zhao/qemu.git  virtual_PMU
[3] http://people.linaro.org/~shannon.zhao/PMU/perf-test-host.txt
[4] http://people.linaro.org/~shannon.zhao/PMU/perf-test-guest.txt
[5] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-host.txt
[6] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-guest.txt

Changes since v6:
* Rebase on v4.4-rc5
* Drop access_pmu_cp15_regs() so that it could use same handler for both
  arch64 and arch32. And it could drop the definitions of CP15 register
  offsets 
* Use vcpu_sys_reg() when accessing PMU registers to avoid endian things
* Add handler for PMUSERENR and some checkers for other registers
* Add kvm_arm_pmu_get_attr()

Changes since v5:
* Rebase on new linux kernel mainline
* Remove state duplications and drop PMOVSCLR, PMCNTENCLR, PMINTENCLR,
  PMXEVCNTR, PMXEVTYPER
* Add a helper to check if vPMU is already initialized
* remove kvm_vcpu from kvm_pmc

Changes since v4:
* Rebase on new linux kernel mainline 
* Drop the reset handler of CP15 registers
* Fix a compile failure on arch ARM due to lack of asm/pmu.h
* Refactor the interrupt injecting flow according to Marc's suggestion
* Check the value of PMSELR register
* Calculate the attr.disabled according to PMCR.E and PMCNTENSET/CLR
* Fix some coding style
* Document the vPMU irq range

Changes since v3:
* Rebase on new linux kernel mainline 
* Use ARMV8_MAX_COUNTERS instead of 32
* Reset PMCR.E to zero.
* Trigger overflow for software increment.
* Optimize PMU interrupt inject logic.
* Add handler for E,C,P bits of PMCR
* Fix the overflow bug found by perf_event_tests
* Run 'perf test', 'perf top' and perf_event_tests test suite
* Add exclude_hv = 1 configuration to not count in EL2

Changes since v2:
* Directly use perf raw event type to create perf_event in KVM
* Add a helper vcpu_sysreg_write
* remove unrelated header file

Changes since v1:
* Use switch...case for registers access handler instead of adding
  alone handler for each register
* Try to use the sys_regs to store the register value instead of adding
  new variables in struct kvm_pmc
* Fix the handle of cp15 regs
* Create a new kvm device vPMU, then userspace could choose whether to
  create PMU
* Fix the handle of PMU overflow interrupt

Shannon Zhao (19):
  ARM64: Move PMU register related defines to asm/pmu.h
  KVM: ARM64: Define PMU data structure for each vcpu
  KVM: ARM64: Add offset defines for PMU registers
  KVM: ARM64: Add access handler for PMCR register
  KVM: ARM64: Add access handler for PMSELR register
  KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
  KVM: ARM64: PMU: Add perf event map and introduce perf event creating
    function
  KVM: ARM64: Add access handler for event typer register
  KVM: ARM64: Add access handler for event counter register
  KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
  KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
  KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
  KVM: ARM64: Add access handler for PMSWINC register
  KVM: ARM64: Add helper to handle PMCR register bits
  KVM: ARM64: Add access handler for PMUSERENR register
  KVM: ARM64: Add PMU overflow interrupt routing
  KVM: ARM64: Reset PMU state when resetting vcpu
  KVM: ARM64: Free perf event of PMU when destroying vcpu
  KVM: ARM64: Add a new kvm ARM PMU device

 Documentation/virtual/kvm/devices/arm-pmu.txt |  16 +
 arch/arm/kvm/arm.c                            |   3 +
 arch/arm64/include/asm/kvm_asm.h              |  25 +-
 arch/arm64/include/asm/kvm_host.h             |   2 +
 arch/arm64/include/asm/pmu.h                  |  67 +++
 arch/arm64/include/uapi/asm/kvm.h             |   3 +
 arch/arm64/kernel/perf_event.c                |  36 +-
 arch/arm64/kvm/Kconfig                        |   7 +
 arch/arm64/kvm/Makefile                       |   1 +
 arch/arm64/kvm/reset.c                        |   3 +
 arch/arm64/kvm/sys_regs.c                     | 605 ++++++++++++++++++++++++--
 include/kvm/arm_pmu.h                         |  69 +++
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 virt/kvm/arm/pmu.c                            | 474 ++++++++++++++++++++
 virt/kvm/kvm_main.c                           |   4 +
 16 files changed, 1249 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
 create mode 100644 arch/arm64/include/asm/pmu.h
 create mode 100644 include/kvm/arm_pmu.h
 create mode 100644 virt/kvm/arm/pmu.c

-- 
2.0.4



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

* [PATCH v7 00/19] KVM: ARM64: Add guest PMU support
@ 2015-12-15  8:49 ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

This patchset adds guest PMU support for KVM on ARM64. It takes
trap-and-emulate approach. When guest wants to monitor one event, it
will be trapped by KVM and KVM will call perf_event API to create a perf
event and call relevant perf_event APIs to get the count value of event.

Use perf to test this patchset in guest. When using "perf list", it
shows the list of the hardware events and hardware cache events perf
supports. Then use "perf stat -e EVENT" to monitor some event. For
example, use "perf stat -e cycles" to count cpu cycles and
"perf stat -e cache-misses" to count cache misses.

Below are the outputs of "perf stat -r 5 sleep 5" when running in host
and guest.

Host:
 Performance counter stats for 'sleep 5' (5 runs):

          0.549456      task-clock (msec)         #    0.000 CPUs utilized            ( +-  5.68% )
                 1      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
                48      page-faults               #    0.088 M/sec                    ( +-  1.40% )
           1146243      cycles                    #    2.086 GHz                      ( +-  5.71% )
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
            627195      instructions              #    0.55  insns per cycle          ( +- 15.65% )
   <not supported>      branches
              9826      branch-misses             #   17.883 M/sec                    ( +-  1.10% )

       5.000875516 seconds time elapsed                                          ( +-  0.00% )


Guest:
 Performance counter stats for 'sleep 5' (5 runs):

          0.640712      task-clock (msec)         #    0.000 CPUs utilized            ( +-  0.41% )
                 1      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
                50      page-faults               #    0.077 M/sec                    ( +-  1.37% )
           1320428      cycles                    #    2.061 GHz                      ( +-  0.29% )
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
            642373      instructions              #    0.49  insns per cycle          ( +-  0.46% )
   <not supported>      branches
             10399      branch-misses             #   16.230 M/sec                    ( +-  1.57% )

       5.001181020 seconds time elapsed                                          ( +-  0.00% )


Have a cycle counter read test like below in guest and host:

static void test(void)
{
	unsigned long count, count1, count2;
	count1 = read_cycles();
	count++;
	count2 = read_cycles();
}

Host:
count1: 3049567104
count2: 3049567247
delta: 143

Guest:
count1: 5281420890
count2: 5281421068
delta: 178

The gap between guest and host is very small. One reason for this I
think is that it doesn't count the cycles in EL2 and host since we add
exclude_hv = 1. So the cycles spent to store/restore registers which
happens at EL2 are not included.

This patchset can be fetched from [1] and the relevant QEMU version for
test can be fetched from [2].

The results of 'perf test' can be found from [3][4].
The results of perf_event_tests test suite can be found from [5][6].

Also, I have tested "perf top" in two VMs and host at the same time. It
works well.

Thanks,
Shannon

[1] https://git.linaro.org/people/shannon.zhao/linux-mainline.git  KVM_ARM64_PMU_v7
[2] https://git.linaro.org/people/shannon.zhao/qemu.git  virtual_PMU
[3] http://people.linaro.org/~shannon.zhao/PMU/perf-test-host.txt
[4] http://people.linaro.org/~shannon.zhao/PMU/perf-test-guest.txt
[5] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-host.txt
[6] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-guest.txt

Changes since v6:
* Rebase on v4.4-rc5
* Drop access_pmu_cp15_regs() so that it could use same handler for both
  arch64 and arch32. And it could drop the definitions of CP15 register
  offsets 
* Use vcpu_sys_reg() when accessing PMU registers to avoid endian things
* Add handler for PMUSERENR and some checkers for other registers
* Add kvm_arm_pmu_get_attr()

Changes since v5:
* Rebase on new linux kernel mainline
* Remove state duplications and drop PMOVSCLR, PMCNTENCLR, PMINTENCLR,
  PMXEVCNTR, PMXEVTYPER
* Add a helper to check if vPMU is already initialized
* remove kvm_vcpu from kvm_pmc

Changes since v4:
* Rebase on new linux kernel mainline 
* Drop the reset handler of CP15 registers
* Fix a compile failure on arch ARM due to lack of asm/pmu.h
* Refactor the interrupt injecting flow according to Marc's suggestion
* Check the value of PMSELR register
* Calculate the attr.disabled according to PMCR.E and PMCNTENSET/CLR
* Fix some coding style
* Document the vPMU irq range

Changes since v3:
* Rebase on new linux kernel mainline 
* Use ARMV8_MAX_COUNTERS instead of 32
* Reset PMCR.E to zero.
* Trigger overflow for software increment.
* Optimize PMU interrupt inject logic.
* Add handler for E,C,P bits of PMCR
* Fix the overflow bug found by perf_event_tests
* Run 'perf test', 'perf top' and perf_event_tests test suite
* Add exclude_hv = 1 configuration to not count in EL2

Changes since v2:
* Directly use perf raw event type to create perf_event in KVM
* Add a helper vcpu_sysreg_write
* remove unrelated header file

Changes since v1:
* Use switch...case for registers access handler instead of adding
  alone handler for each register
* Try to use the sys_regs to store the register value instead of adding
  new variables in struct kvm_pmc
* Fix the handle of cp15 regs
* Create a new kvm device vPMU, then userspace could choose whether to
  create PMU
* Fix the handle of PMU overflow interrupt

Shannon Zhao (19):
  ARM64: Move PMU register related defines to asm/pmu.h
  KVM: ARM64: Define PMU data structure for each vcpu
  KVM: ARM64: Add offset defines for PMU registers
  KVM: ARM64: Add access handler for PMCR register
  KVM: ARM64: Add access handler for PMSELR register
  KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
  KVM: ARM64: PMU: Add perf event map and introduce perf event creating
    function
  KVM: ARM64: Add access handler for event typer register
  KVM: ARM64: Add access handler for event counter register
  KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
  KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
  KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
  KVM: ARM64: Add access handler for PMSWINC register
  KVM: ARM64: Add helper to handle PMCR register bits
  KVM: ARM64: Add access handler for PMUSERENR register
  KVM: ARM64: Add PMU overflow interrupt routing
  KVM: ARM64: Reset PMU state when resetting vcpu
  KVM: ARM64: Free perf event of PMU when destroying vcpu
  KVM: ARM64: Add a new kvm ARM PMU device

 Documentation/virtual/kvm/devices/arm-pmu.txt |  16 +
 arch/arm/kvm/arm.c                            |   3 +
 arch/arm64/include/asm/kvm_asm.h              |  25 +-
 arch/arm64/include/asm/kvm_host.h             |   2 +
 arch/arm64/include/asm/pmu.h                  |  67 +++
 arch/arm64/include/uapi/asm/kvm.h             |   3 +
 arch/arm64/kernel/perf_event.c                |  36 +-
 arch/arm64/kvm/Kconfig                        |   7 +
 arch/arm64/kvm/Makefile                       |   1 +
 arch/arm64/kvm/reset.c                        |   3 +
 arch/arm64/kvm/sys_regs.c                     | 605 ++++++++++++++++++++++++--
 include/kvm/arm_pmu.h                         |  69 +++
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 virt/kvm/arm/pmu.c                            | 474 ++++++++++++++++++++
 virt/kvm/kvm_main.c                           |   4 +
 16 files changed, 1249 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
 create mode 100644 arch/arm64/include/asm/pmu.h
 create mode 100644 include/kvm/arm_pmu.h
 create mode 100644 virt/kvm/arm/pmu.c

-- 
2.0.4



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

* [PATCH v7 00/19] KVM: ARM64: Add guest PMU support
@ 2015-12-15  8:49 ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

This patchset adds guest PMU support for KVM on ARM64. It takes
trap-and-emulate approach. When guest wants to monitor one event, it
will be trapped by KVM and KVM will call perf_event API to create a perf
event and call relevant perf_event APIs to get the count value of event.

Use perf to test this patchset in guest. When using "perf list", it
shows the list of the hardware events and hardware cache events perf
supports. Then use "perf stat -e EVENT" to monitor some event. For
example, use "perf stat -e cycles" to count cpu cycles and
"perf stat -e cache-misses" to count cache misses.

Below are the outputs of "perf stat -r 5 sleep 5" when running in host
and guest.

Host:
 Performance counter stats for 'sleep 5' (5 runs):

          0.549456      task-clock (msec)         #    0.000 CPUs utilized            ( +-  5.68% )
                 1      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
                48      page-faults               #    0.088 M/sec                    ( +-  1.40% )
           1146243      cycles                    #    2.086 GHz                      ( +-  5.71% )
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
            627195      instructions              #    0.55  insns per cycle          ( +- 15.65% )
   <not supported>      branches
              9826      branch-misses             #   17.883 M/sec                    ( +-  1.10% )

       5.000875516 seconds time elapsed                                          ( +-  0.00% )


Guest:
 Performance counter stats for 'sleep 5' (5 runs):

          0.640712      task-clock (msec)         #    0.000 CPUs utilized            ( +-  0.41% )
                 1      context-switches          #    0.002 M/sec
                 0      cpu-migrations            #    0.000 K/sec
                50      page-faults               #    0.077 M/sec                    ( +-  1.37% )
           1320428      cycles                    #    2.061 GHz                      ( +-  0.29% )
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
            642373      instructions              #    0.49  insns per cycle          ( +-  0.46% )
   <not supported>      branches
             10399      branch-misses             #   16.230 M/sec                    ( +-  1.57% )

       5.001181020 seconds time elapsed                                          ( +-  0.00% )


Have a cycle counter read test like below in guest and host:

static void test(void)
{
	unsigned long count, count1, count2;
	count1 = read_cycles();
	count++;
	count2 = read_cycles();
}

Host:
count1: 3049567104
count2: 3049567247
delta: 143

Guest:
count1: 5281420890
count2: 5281421068
delta: 178

The gap between guest and host is very small. One reason for this I
think is that it doesn't count the cycles in EL2 and host since we add
exclude_hv = 1. So the cycles spent to store/restore registers which
happens at EL2 are not included.

This patchset can be fetched from [1] and the relevant QEMU version for
test can be fetched from [2].

The results of 'perf test' can be found from [3][4].
The results of perf_event_tests test suite can be found from [5][6].

Also, I have tested "perf top" in two VMs and host at the same time. It
works well.

Thanks,
Shannon

[1] https://git.linaro.org/people/shannon.zhao/linux-mainline.git  KVM_ARM64_PMU_v7
[2] https://git.linaro.org/people/shannon.zhao/qemu.git  virtual_PMU
[3] http://people.linaro.org/~shannon.zhao/PMU/perf-test-host.txt
[4] http://people.linaro.org/~shannon.zhao/PMU/perf-test-guest.txt
[5] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-host.txt
[6] http://people.linaro.org/~shannon.zhao/PMU/perf_event_tests-guest.txt

Changes since v6:
* Rebase on v4.4-rc5
* Drop access_pmu_cp15_regs() so that it could use same handler for both
  arch64 and arch32. And it could drop the definitions of CP15 register
  offsets 
* Use vcpu_sys_reg() when accessing PMU registers to avoid endian things
* Add handler for PMUSERENR and some checkers for other registers
* Add kvm_arm_pmu_get_attr()

Changes since v5:
* Rebase on new linux kernel mainline
* Remove state duplications and drop PMOVSCLR, PMCNTENCLR, PMINTENCLR,
  PMXEVCNTR, PMXEVTYPER
* Add a helper to check if vPMU is already initialized
* remove kvm_vcpu from kvm_pmc

Changes since v4:
* Rebase on new linux kernel mainline 
* Drop the reset handler of CP15 registers
* Fix a compile failure on arch ARM due to lack of asm/pmu.h
* Refactor the interrupt injecting flow according to Marc's suggestion
* Check the value of PMSELR register
* Calculate the attr.disabled according to PMCR.E and PMCNTENSET/CLR
* Fix some coding style
* Document the vPMU irq range

Changes since v3:
* Rebase on new linux kernel mainline 
* Use ARMV8_MAX_COUNTERS instead of 32
* Reset PMCR.E to zero.
* Trigger overflow for software increment.
* Optimize PMU interrupt inject logic.
* Add handler for E,C,P bits of PMCR
* Fix the overflow bug found by perf_event_tests
* Run 'perf test', 'perf top' and perf_event_tests test suite
* Add exclude_hv = 1 configuration to not count in EL2

Changes since v2:
* Directly use perf raw event type to create perf_event in KVM
* Add a helper vcpu_sysreg_write
* remove unrelated header file

Changes since v1:
* Use switch...case for registers access handler instead of adding
  alone handler for each register
* Try to use the sys_regs to store the register value instead of adding
  new variables in struct kvm_pmc
* Fix the handle of cp15 regs
* Create a new kvm device vPMU, then userspace could choose whether to
  create PMU
* Fix the handle of PMU overflow interrupt

Shannon Zhao (19):
  ARM64: Move PMU register related defines to asm/pmu.h
  KVM: ARM64: Define PMU data structure for each vcpu
  KVM: ARM64: Add offset defines for PMU registers
  KVM: ARM64: Add access handler for PMCR register
  KVM: ARM64: Add access handler for PMSELR register
  KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
  KVM: ARM64: PMU: Add perf event map and introduce perf event creating
    function
  KVM: ARM64: Add access handler for event typer register
  KVM: ARM64: Add access handler for event counter register
  KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
  KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
  KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
  KVM: ARM64: Add access handler for PMSWINC register
  KVM: ARM64: Add helper to handle PMCR register bits
  KVM: ARM64: Add access handler for PMUSERENR register
  KVM: ARM64: Add PMU overflow interrupt routing
  KVM: ARM64: Reset PMU state when resetting vcpu
  KVM: ARM64: Free perf event of PMU when destroying vcpu
  KVM: ARM64: Add a new kvm ARM PMU device

 Documentation/virtual/kvm/devices/arm-pmu.txt |  16 +
 arch/arm/kvm/arm.c                            |   3 +
 arch/arm64/include/asm/kvm_asm.h              |  25 +-
 arch/arm64/include/asm/kvm_host.h             |   2 +
 arch/arm64/include/asm/pmu.h                  |  67 +++
 arch/arm64/include/uapi/asm/kvm.h             |   3 +
 arch/arm64/kernel/perf_event.c                |  36 +-
 arch/arm64/kvm/Kconfig                        |   7 +
 arch/arm64/kvm/Makefile                       |   1 +
 arch/arm64/kvm/reset.c                        |   3 +
 arch/arm64/kvm/sys_regs.c                     | 605 ++++++++++++++++++++++++--
 include/kvm/arm_pmu.h                         |  69 +++
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 virt/kvm/arm/pmu.c                            | 474 ++++++++++++++++++++
 virt/kvm/kvm_main.c                           |   4 +
 16 files changed, 1249 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
 create mode 100644 arch/arm64/include/asm/pmu.h
 create mode 100644 include/kvm/arm_pmu.h
 create mode 100644 virt/kvm/arm/pmu.c

-- 
2.0.4

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

* [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

To use the ARMv8 PMU related register defines from the KVM code,
we move the relevant definitions to asm/pmu.h header file.

Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/pmu.h   | 64 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/perf_event.c | 36 +-----------------------
 2 files changed, 65 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm64/include/asm/pmu.h

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
new file mode 100644
index 0000000..4264ea0
--- /dev/null
+++ b/arch/arm64/include/asm/pmu.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd, Shannon Zhao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PMU_H
+#define __ASM_PMU_H
+
+#define ARMV8_MAX_COUNTERS      32
+#define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
+
+/*
+ * Per-CPU PMCR: config reg
+ */
+#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
+#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
+#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
+#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
+#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
+#define	ARMV8_PMCR_N_MASK	0x1f
+#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
+
+/*
+ * PMCNTEN: counters enable reg
+ */
+#define	ARMV8_CNTEN_MASK	0xffffffff	/* Mask for writable bits */
+
+/*
+ * PMINTEN: counters interrupt enable reg
+ */
+#define	ARMV8_INTEN_MASK	0xffffffff	/* Mask for writable bits */
+
+/*
+ * PMOVSR: counters overflow flag status reg
+ */
+#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
+#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
+
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
+#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
+
+/*
+ * Event filters for PMUv3
+ */
+#define	ARMV8_EXCLUDE_EL1	(1 << 31)
+#define	ARMV8_EXCLUDE_EL0	(1 << 30)
+#define	ARMV8_INCLUDE_EL2	(1 << 27)
+
+#endif /* __ASM_PMU_H */
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5b1897e..7eca5dc 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
+#include <asm/pmu.h>
 
 /*
  * ARMv8 PMUv3 Performance Events handling code.
@@ -187,9 +188,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #define	ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
 	(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
 
-#define	ARMV8_MAX_COUNTERS	32
-#define	ARMV8_COUNTER_MASK	(ARMV8_MAX_COUNTERS - 1)
-
 /*
  * ARMv8 low level PMU access
  */
@@ -200,38 +198,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #define	ARMV8_IDX_TO_COUNTER(x)	\
 	(((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
 
-/*
- * Per-CPU PMCR: config reg
- */
-#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
-#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
-#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
-#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
-#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
-#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
-#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
-#define	ARMV8_PMCR_N_MASK	0x1f
-#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
-
-/*
- * PMOVSR: counters overflow flag status reg
- */
-#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
-#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
-
-/*
- * PMXEVTYPER: Event selection reg
- */
-#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
-#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
-
-/*
- * Event filters for PMUv3
- */
-#define	ARMV8_EXCLUDE_EL1	(1 << 31)
-#define	ARMV8_EXCLUDE_EL0	(1 << 30)
-#define	ARMV8_INCLUDE_EL2	(1 << 27)
-
 static inline u32 armv8pmu_pmcr_read(void)
 {
 	u32 val;
-- 
2.0.4

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

* [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

To use the ARMv8 PMU related register defines from the KVM code,
we move the relevant definitions to asm/pmu.h header file.

Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/pmu.h   | 64 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/perf_event.c | 36 +-----------------------
 2 files changed, 65 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm64/include/asm/pmu.h

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
new file mode 100644
index 0000000..4264ea0
--- /dev/null
+++ b/arch/arm64/include/asm/pmu.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd, Shannon Zhao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PMU_H
+#define __ASM_PMU_H
+
+#define ARMV8_MAX_COUNTERS      32
+#define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
+
+/*
+ * Per-CPU PMCR: config reg
+ */
+#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
+#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
+#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
+#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
+#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
+#define	ARMV8_PMCR_N_MASK	0x1f
+#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
+
+/*
+ * PMCNTEN: counters enable reg
+ */
+#define	ARMV8_CNTEN_MASK	0xffffffff	/* Mask for writable bits */
+
+/*
+ * PMINTEN: counters interrupt enable reg
+ */
+#define	ARMV8_INTEN_MASK	0xffffffff	/* Mask for writable bits */
+
+/*
+ * PMOVSR: counters overflow flag status reg
+ */
+#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
+#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
+
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
+#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
+
+/*
+ * Event filters for PMUv3
+ */
+#define	ARMV8_EXCLUDE_EL1	(1 << 31)
+#define	ARMV8_EXCLUDE_EL0	(1 << 30)
+#define	ARMV8_INCLUDE_EL2	(1 << 27)
+
+#endif /* __ASM_PMU_H */
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5b1897e..7eca5dc 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
+#include <asm/pmu.h>
 
 /*
  * ARMv8 PMUv3 Performance Events handling code.
@@ -187,9 +188,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #define	ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
 	(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
 
-#define	ARMV8_MAX_COUNTERS	32
-#define	ARMV8_COUNTER_MASK	(ARMV8_MAX_COUNTERS - 1)
-
 /*
  * ARMv8 low level PMU access
  */
@@ -200,38 +198,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #define	ARMV8_IDX_TO_COUNTER(x)	\
 	(((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
 
-/*
- * Per-CPU PMCR: config reg
- */
-#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
-#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
-#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
-#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
-#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
-#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
-#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
-#define	ARMV8_PMCR_N_MASK	0x1f
-#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
-
-/*
- * PMOVSR: counters overflow flag status reg
- */
-#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
-#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
-
-/*
- * PMXEVTYPER: Event selection reg
- */
-#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
-#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
-
-/*
- * Event filters for PMUv3
- */
-#define	ARMV8_EXCLUDE_EL1	(1 << 31)
-#define	ARMV8_EXCLUDE_EL0	(1 << 30)
-#define	ARMV8_INCLUDE_EL2	(1 << 27)
-
 static inline u32 armv8pmu_pmcr_read(void)
 {
 	u32 val;
-- 
2.0.4

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

* [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

To use the ARMv8 PMU related register defines from the KVM code,
we move the relevant definitions to asm/pmu.h header file.

Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/pmu.h   | 64 ++++++++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/perf_event.c | 36 +-----------------------
 2 files changed, 65 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm64/include/asm/pmu.h

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
new file mode 100644
index 0000000..4264ea0
--- /dev/null
+++ b/arch/arm64/include/asm/pmu.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd, Shannon Zhao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_PMU_H
+#define __ASM_PMU_H
+
+#define ARMV8_MAX_COUNTERS      32
+#define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
+
+/*
+ * Per-CPU PMCR: config reg
+ */
+#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
+#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
+#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
+#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
+#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
+#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
+#define	ARMV8_PMCR_N_MASK	0x1f
+#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
+
+/*
+ * PMCNTEN: counters enable reg
+ */
+#define	ARMV8_CNTEN_MASK	0xffffffff	/* Mask for writable bits */
+
+/*
+ * PMINTEN: counters interrupt enable reg
+ */
+#define	ARMV8_INTEN_MASK	0xffffffff	/* Mask for writable bits */
+
+/*
+ * PMOVSR: counters overflow flag status reg
+ */
+#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
+#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
+
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
+#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
+
+/*
+ * Event filters for PMUv3
+ */
+#define	ARMV8_EXCLUDE_EL1	(1 << 31)
+#define	ARMV8_EXCLUDE_EL0	(1 << 30)
+#define	ARMV8_INCLUDE_EL2	(1 << 27)
+
+#endif /* __ASM_PMU_H */
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5b1897e..7eca5dc 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
+#include <asm/pmu.h>
 
 /*
  * ARMv8 PMUv3 Performance Events handling code.
@@ -187,9 +188,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #define	ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
 	(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
 
-#define	ARMV8_MAX_COUNTERS	32
-#define	ARMV8_COUNTER_MASK	(ARMV8_MAX_COUNTERS - 1)
-
 /*
  * ARMv8 low level PMU access
  */
@@ -200,38 +198,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
 #define	ARMV8_IDX_TO_COUNTER(x)	\
 	(((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
 
-/*
- * Per-CPU PMCR: config reg
- */
-#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
-#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
-#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
-#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
-#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
-#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
-#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
-#define	ARMV8_PMCR_N_MASK	0x1f
-#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
-
-/*
- * PMOVSR: counters overflow flag status reg
- */
-#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
-#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
-
-/*
- * PMXEVTYPER: Event selection reg
- */
-#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
-#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
-
-/*
- * Event filters for PMUv3
- */
-#define	ARMV8_EXCLUDE_EL1	(1 << 31)
-#define	ARMV8_EXCLUDE_EL0	(1 << 30)
-#define	ARMV8_INCLUDE_EL2	(1 << 27)
-
 static inline u32 armv8pmu_pmcr_read(void)
 {
 	u32 val;
-- 
2.0.4

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

* [PATCH v7 02/19] KVM: ARM64: Define PMU data structure for each vcpu
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Here we plan to support virtual PMU for guest by full software
emulation, so define some basic structs and functions preparing for
futher steps. Define struct kvm_pmc for performance monitor counter and
struct kvm_pmu for performance monitor unit for each vcpu. According to
ARMv8 spec, the PMU contains at most 32(ARMV8_MAX_COUNTERS) counters.

Since this only supports ARM64 (or PMUv3), add a separate config symbol
for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/Kconfig            |  7 +++++++
 include/kvm/arm_pmu.h             | 42 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)
 create mode 100644 include/kvm/arm_pmu.h

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a35ce72..42e15bb 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -37,6 +37,7 @@
 
 #include <kvm/arm_vgic.h>
 #include <kvm/arm_arch_timer.h>
+#include <kvm/arm_pmu.h>
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
@@ -132,6 +133,7 @@ struct kvm_vcpu_arch {
 	/* VGIC state */
 	struct vgic_cpu vgic_cpu;
 	struct arch_timer_cpu timer_cpu;
+	struct kvm_pmu pmu;
 
 	/*
 	 * Anything that is not used directly from assembly code goes
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index a5272c0..de7450d 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -36,6 +36,7 @@ config KVM
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
 	select KVM_ARM_VGIC_V3
+	select KVM_ARM_PMU if HW_PERF_EVENTS
 	---help---
 	  Support hosting virtualized guest machines.
 	  We don't support KVM with 16K page tables yet, due to the multiple
@@ -48,6 +49,12 @@ config KVM_ARM_HOST
 	---help---
 	  Provides host support for ARM processors.
 
+config KVM_ARM_PMU
+	bool
+	---help---
+	  Adds support for a virtual Performance Monitoring Unit (PMU) in
+	  virtual machines.
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
new file mode 100644
index 0000000..ddcb5b2
--- /dev/null
+++ b/include/kvm/arm_pmu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao <shannon.zhao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_ARM_KVM_PMU_H
+#define __ASM_ARM_KVM_PMU_H
+
+#ifdef CONFIG_KVM_ARM_PMU
+
+#include <linux/perf_event.h>
+#include <asm/pmu.h>
+
+struct kvm_pmc {
+	u8 idx;/* index into the pmu->pmc array */
+	struct perf_event *perf_event;
+	u64 bitmask;
+};
+
+struct kvm_pmu {
+	/* PMU IRQ Number per VCPU */
+	int irq_num;
+	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
+};
+#else
+struct kvm_pmu {
+};
+#endif
+
+#endif
-- 
2.0.4

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

* [PATCH v7 02/19] KVM: ARM64: Define PMU data structure for each vcpu
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Here we plan to support virtual PMU for guest by full software
emulation, so define some basic structs and functions preparing for
futher steps. Define struct kvm_pmc for performance monitor counter and
struct kvm_pmu for performance monitor unit for each vcpu. According to
ARMv8 spec, the PMU contains at most 32(ARMV8_MAX_COUNTERS) counters.

Since this only supports ARM64 (or PMUv3), add a separate config symbol
for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/Kconfig            |  7 +++++++
 include/kvm/arm_pmu.h             | 42 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)
 create mode 100644 include/kvm/arm_pmu.h

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a35ce72..42e15bb 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -37,6 +37,7 @@
 
 #include <kvm/arm_vgic.h>
 #include <kvm/arm_arch_timer.h>
+#include <kvm/arm_pmu.h>
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
@@ -132,6 +133,7 @@ struct kvm_vcpu_arch {
 	/* VGIC state */
 	struct vgic_cpu vgic_cpu;
 	struct arch_timer_cpu timer_cpu;
+	struct kvm_pmu pmu;
 
 	/*
 	 * Anything that is not used directly from assembly code goes
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index a5272c0..de7450d 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -36,6 +36,7 @@ config KVM
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
 	select KVM_ARM_VGIC_V3
+	select KVM_ARM_PMU if HW_PERF_EVENTS
 	---help---
 	  Support hosting virtualized guest machines.
 	  We don't support KVM with 16K page tables yet, due to the multiple
@@ -48,6 +49,12 @@ config KVM_ARM_HOST
 	---help---
 	  Provides host support for ARM processors.
 
+config KVM_ARM_PMU
+	bool
+	---help---
+	  Adds support for a virtual Performance Monitoring Unit (PMU) in
+	  virtual machines.
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
new file mode 100644
index 0000000..ddcb5b2
--- /dev/null
+++ b/include/kvm/arm_pmu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao <shannon.zhao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_ARM_KVM_PMU_H
+#define __ASM_ARM_KVM_PMU_H
+
+#ifdef CONFIG_KVM_ARM_PMU
+
+#include <linux/perf_event.h>
+#include <asm/pmu.h>
+
+struct kvm_pmc {
+	u8 idx;/* index into the pmu->pmc array */
+	struct perf_event *perf_event;
+	u64 bitmask;
+};
+
+struct kvm_pmu {
+	/* PMU IRQ Number per VCPU */
+	int irq_num;
+	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
+};
+#else
+struct kvm_pmu {
+};
+#endif
+
+#endif
-- 
2.0.4

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

* [PATCH v7 02/19] KVM: ARM64: Define PMU data structure for each vcpu
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Here we plan to support virtual PMU for guest by full software
emulation, so define some basic structs and functions preparing for
futher steps. Define struct kvm_pmc for performance monitor counter and
struct kvm_pmu for performance monitor unit for each vcpu. According to
ARMv8 spec, the PMU contains at most 32(ARMV8_MAX_COUNTERS) counters.

Since this only supports ARM64 (or PMUv3), add a separate config symbol
for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/Kconfig            |  7 +++++++
 include/kvm/arm_pmu.h             | 42 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)
 create mode 100644 include/kvm/arm_pmu.h

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a35ce72..42e15bb 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -37,6 +37,7 @@
 
 #include <kvm/arm_vgic.h>
 #include <kvm/arm_arch_timer.h>
+#include <kvm/arm_pmu.h>
 
 #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS
 
@@ -132,6 +133,7 @@ struct kvm_vcpu_arch {
 	/* VGIC state */
 	struct vgic_cpu vgic_cpu;
 	struct arch_timer_cpu timer_cpu;
+	struct kvm_pmu pmu;
 
 	/*
 	 * Anything that is not used directly from assembly code goes
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
index a5272c0..de7450d 100644
--- a/arch/arm64/kvm/Kconfig
+++ b/arch/arm64/kvm/Kconfig
@@ -36,6 +36,7 @@ config KVM
 	select HAVE_KVM_EVENTFD
 	select HAVE_KVM_IRQFD
 	select KVM_ARM_VGIC_V3
+	select KVM_ARM_PMU if HW_PERF_EVENTS
 	---help---
 	  Support hosting virtualized guest machines.
 	  We don't support KVM with 16K page tables yet, due to the multiple
@@ -48,6 +49,12 @@ config KVM_ARM_HOST
 	---help---
 	  Provides host support for ARM processors.
 
+config KVM_ARM_PMU
+	bool
+	---help---
+	  Adds support for a virtual Performance Monitoring Unit (PMU) in
+	  virtual machines.
+
 source drivers/vhost/Kconfig
 
 endif # VIRTUALIZATION
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
new file mode 100644
index 0000000..ddcb5b2
--- /dev/null
+++ b/include/kvm/arm_pmu.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao <shannon.zhao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_ARM_KVM_PMU_H
+#define __ASM_ARM_KVM_PMU_H
+
+#ifdef CONFIG_KVM_ARM_PMU
+
+#include <linux/perf_event.h>
+#include <asm/pmu.h>
+
+struct kvm_pmc {
+	u8 idx;/* index into the pmu->pmc array */
+	struct perf_event *perf_event;
+	u64 bitmask;
+};
+
+struct kvm_pmu {
+	/* PMU IRQ Number per VCPU */
+	int irq_num;
+	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
+};
+#else
+struct kvm_pmu {
+};
+#endif
+
+#endif
-- 
2.0.4

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

* [PATCH v7 03/19] KVM: ARM64: Add offset defines for PMU registers
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

We are about to trap and emulate accesses to each PMU register
individually. This adds the context offsets for the AArch64 PMU
registers.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/kvm_asm.h | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 5e37710..1aef220 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -48,12 +48,27 @@
 #define MDSCR_EL1	22	/* Monitor Debug System Control Register */
 #define MDCCINT_EL1	23	/* Monitor Debug Comms Channel Interrupt Enable Reg */
 
+/* Performance Monitors Registers */
+#define PMCR_EL0	24	/* Control Register */
+#define PMOVSSET_EL0	25	/* Overflow Flag Status Set Register */
+#define PMSELR_EL0	26	/* Event Counter Selection Register */
+#define PMEVCNTR0_EL0	27	/* Event Counter Register (0-30) */
+#define PMEVCNTR30_EL0	57
+#define PMCCNTR_EL0	58	/* Cycle Counter Register */
+#define PMEVTYPER0_EL0	59	/* Event Type Register (0-30) */
+#define PMEVTYPER30_EL0	89
+#define PMCCFILTR_EL0	90	/* Cycle Count Filter Register */
+#define PMCNTENSET_EL0	91	/* Count Enable Set Register */
+#define PMINTENSET_EL1	92	/* Interrupt Enable Set Register */
+#define PMUSERENR_EL0	93	/* User Enable Register */
+#define PMSWINC_EL0	94	/* Software Increment Register */
+
 /* 32bit specific registers. Keep them at the end of the range */
-#define	DACR32_EL2	24	/* Domain Access Control Register */
-#define	IFSR32_EL2	25	/* Instruction Fault Status Register */
-#define	FPEXC32_EL2	26	/* Floating-Point Exception Control Register */
-#define	DBGVCR32_EL2	27	/* Debug Vector Catch Register */
-#define	NR_SYS_REGS	28
+#define	DACR32_EL2	95	/* Domain Access Control Register */
+#define	IFSR32_EL2	96	/* Instruction Fault Status Register */
+#define	FPEXC32_EL2	97	/* Floating-Point Exception Control Register */
+#define	DBGVCR32_EL2	98	/* Debug Vector Catch Register */
+#define	NR_SYS_REGS	99
 
 /* 32bit mapping */
 #define c0_MPIDR	(MPIDR_EL1 * 2)	/* MultiProcessor ID Register */
-- 
2.0.4

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

* [PATCH v7 03/19] KVM: ARM64: Add offset defines for PMU registers
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

We are about to trap and emulate accesses to each PMU register
individually. This adds the context offsets for the AArch64 PMU
registers.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/kvm_asm.h | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 5e37710..1aef220 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -48,12 +48,27 @@
 #define MDSCR_EL1	22	/* Monitor Debug System Control Register */
 #define MDCCINT_EL1	23	/* Monitor Debug Comms Channel Interrupt Enable Reg */
 
+/* Performance Monitors Registers */
+#define PMCR_EL0	24	/* Control Register */
+#define PMOVSSET_EL0	25	/* Overflow Flag Status Set Register */
+#define PMSELR_EL0	26	/* Event Counter Selection Register */
+#define PMEVCNTR0_EL0	27	/* Event Counter Register (0-30) */
+#define PMEVCNTR30_EL0	57
+#define PMCCNTR_EL0	58	/* Cycle Counter Register */
+#define PMEVTYPER0_EL0	59	/* Event Type Register (0-30) */
+#define PMEVTYPER30_EL0	89
+#define PMCCFILTR_EL0	90	/* Cycle Count Filter Register */
+#define PMCNTENSET_EL0	91	/* Count Enable Set Register */
+#define PMINTENSET_EL1	92	/* Interrupt Enable Set Register */
+#define PMUSERENR_EL0	93	/* User Enable Register */
+#define PMSWINC_EL0	94	/* Software Increment Register */
+
 /* 32bit specific registers. Keep them at the end of the range */
-#define	DACR32_EL2	24	/* Domain Access Control Register */
-#define	IFSR32_EL2	25	/* Instruction Fault Status Register */
-#define	FPEXC32_EL2	26	/* Floating-Point Exception Control Register */
-#define	DBGVCR32_EL2	27	/* Debug Vector Catch Register */
-#define	NR_SYS_REGS	28
+#define	DACR32_EL2	95	/* Domain Access Control Register */
+#define	IFSR32_EL2	96	/* Instruction Fault Status Register */
+#define	FPEXC32_EL2	97	/* Floating-Point Exception Control Register */
+#define	DBGVCR32_EL2	98	/* Debug Vector Catch Register */
+#define	NR_SYS_REGS	99
 
 /* 32bit mapping */
 #define c0_MPIDR	(MPIDR_EL1 * 2)	/* MultiProcessor ID Register */
-- 
2.0.4

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

* [PATCH v7 03/19] KVM: ARM64: Add offset defines for PMU registers
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

We are about to trap and emulate accesses to each PMU register
individually. This adds the context offsets for the AArch64 PMU
registers.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/kvm_asm.h | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 5e37710..1aef220 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -48,12 +48,27 @@
 #define MDSCR_EL1	22	/* Monitor Debug System Control Register */
 #define MDCCINT_EL1	23	/* Monitor Debug Comms Channel Interrupt Enable Reg */
 
+/* Performance Monitors Registers */
+#define PMCR_EL0	24	/* Control Register */
+#define PMOVSSET_EL0	25	/* Overflow Flag Status Set Register */
+#define PMSELR_EL0	26	/* Event Counter Selection Register */
+#define PMEVCNTR0_EL0	27	/* Event Counter Register (0-30) */
+#define PMEVCNTR30_EL0	57
+#define PMCCNTR_EL0	58	/* Cycle Counter Register */
+#define PMEVTYPER0_EL0	59	/* Event Type Register (0-30) */
+#define PMEVTYPER30_EL0	89
+#define PMCCFILTR_EL0	90	/* Cycle Count Filter Register */
+#define PMCNTENSET_EL0	91	/* Count Enable Set Register */
+#define PMINTENSET_EL1	92	/* Interrupt Enable Set Register */
+#define PMUSERENR_EL0	93	/* User Enable Register */
+#define PMSWINC_EL0	94	/* Software Increment Register */
+
 /* 32bit specific registers. Keep them at the end of the range */
-#define	DACR32_EL2	24	/* Domain Access Control Register */
-#define	IFSR32_EL2	25	/* Instruction Fault Status Register */
-#define	FPEXC32_EL2	26	/* Floating-Point Exception Control Register */
-#define	DBGVCR32_EL2	27	/* Debug Vector Catch Register */
-#define	NR_SYS_REGS	28
+#define	DACR32_EL2	95	/* Domain Access Control Register */
+#define	IFSR32_EL2	96	/* Instruction Fault Status Register */
+#define	FPEXC32_EL2	97	/* Floating-Point Exception Control Register */
+#define	DBGVCR32_EL2	98	/* Debug Vector Catch Register */
+#define	NR_SYS_REGS	99
 
 /* 32bit mapping */
 #define c0_MPIDR	(MPIDR_EL1 * 2)	/* MultiProcessor ID Register */
-- 
2.0.4

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

* [PATCH v7 04/19] KVM: ARM64: Add access handler for PMCR register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

Add reset handler which gets host value of PMCR_EL0 and make writable
bits architecturally UNKNOWN except PMCR.E which is zero. Add an access
handler for PMCR.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d2650e8..9a06116 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -33,6 +33,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_mmu.h>
+#include <asm/pmu.h>
 
 #include <trace/events/kvm.h>
 
@@ -438,6 +439,40 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
 }
 
+static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+	u64 pmcr, val;
+
+	asm volatile("mrs %0, pmcr_el0\n" : "=r" (pmcr));
+	/* Writable bits of PMCR_EL0 (ARMV8_PMCR_MASK) is reset to UNKNOWN
+	 * except PMCR.E resetting to zero.
+	 */
+	val = ((pmcr & ~ARMV8_PMCR_MASK) | (ARMV8_PMCR_MASK & 0xdecafbad))
+	      & (~ARMV8_PMCR_E);
+	vcpu_sys_reg(vcpu, r->reg) = val;
+}
+
+static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			const struct sys_reg_desc *r)
+{
+	u64 val;
+
+	if (p->is_write) {
+		/* Only update writeable bits of PMCR */
+		val = vcpu_sys_reg(vcpu, r->reg);
+		val &= ~ARMV8_PMCR_MASK;
+		val |= p->regval & ARMV8_PMCR_MASK;
+		vcpu_sys_reg(vcpu, r->reg) = val;
+	} else {
+		/* PMCR.P & PMCR.C are RAZ */
+		val = vcpu_sys_reg(vcpu, r->reg)
+		      & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
+		p->regval = val;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -622,7 +657,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	/* PMCR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmcr, reset_pmcr, PMCR_EL0, },
 	/* PMCNTENSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
 	  trap_raz_wi },
@@ -884,7 +919,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
 
 	/* PMU */
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-- 
2.0.4



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

* [PATCH v7 04/19] KVM: ARM64: Add access handler for PMCR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

Add reset handler which gets host value of PMCR_EL0 and make writable
bits architecturally UNKNOWN except PMCR.E which is zero. Add an access
handler for PMCR.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d2650e8..9a06116 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -33,6 +33,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_mmu.h>
+#include <asm/pmu.h>
 
 #include <trace/events/kvm.h>
 
@@ -438,6 +439,40 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
 }
 
+static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+	u64 pmcr, val;
+
+	asm volatile("mrs %0, pmcr_el0\n" : "=r" (pmcr));
+	/* Writable bits of PMCR_EL0 (ARMV8_PMCR_MASK) is reset to UNKNOWN
+	 * except PMCR.E resetting to zero.
+	 */
+	val = ((pmcr & ~ARMV8_PMCR_MASK) | (ARMV8_PMCR_MASK & 0xdecafbad))
+	      & (~ARMV8_PMCR_E);
+	vcpu_sys_reg(vcpu, r->reg) = val;
+}
+
+static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			const struct sys_reg_desc *r)
+{
+	u64 val;
+
+	if (p->is_write) {
+		/* Only update writeable bits of PMCR */
+		val = vcpu_sys_reg(vcpu, r->reg);
+		val &= ~ARMV8_PMCR_MASK;
+		val |= p->regval & ARMV8_PMCR_MASK;
+		vcpu_sys_reg(vcpu, r->reg) = val;
+	} else {
+		/* PMCR.P & PMCR.C are RAZ */
+		val = vcpu_sys_reg(vcpu, r->reg)
+		      & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
+		p->regval = val;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -622,7 +657,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	/* PMCR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmcr, reset_pmcr, PMCR_EL0, },
 	/* PMCNTENSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
 	  trap_raz_wi },
@@ -884,7 +919,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
 
 	/* PMU */
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-- 
2.0.4



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

* [PATCH v7 04/19] KVM: ARM64: Add access handler for PMCR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Add reset handler which gets host value of PMCR_EL0 and make writable
bits architecturally UNKNOWN except PMCR.E which is zero. Add an access
handler for PMCR.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d2650e8..9a06116 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -33,6 +33,7 @@
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_host.h>
 #include <asm/kvm_mmu.h>
+#include <asm/pmu.h>
 
 #include <trace/events/kvm.h>
 
@@ -438,6 +439,40 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	vcpu_sys_reg(vcpu, MPIDR_EL1) = (1ULL << 31) | mpidr;
 }
 
+static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+	u64 pmcr, val;
+
+	asm volatile("mrs %0, pmcr_el0\n" : "=r" (pmcr));
+	/* Writable bits of PMCR_EL0 (ARMV8_PMCR_MASK) is reset to UNKNOWN
+	 * except PMCR.E resetting to zero.
+	 */
+	val = ((pmcr & ~ARMV8_PMCR_MASK) | (ARMV8_PMCR_MASK & 0xdecafbad))
+	      & (~ARMV8_PMCR_E);
+	vcpu_sys_reg(vcpu, r->reg) = val;
+}
+
+static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			const struct sys_reg_desc *r)
+{
+	u64 val;
+
+	if (p->is_write) {
+		/* Only update writeable bits of PMCR */
+		val = vcpu_sys_reg(vcpu, r->reg);
+		val &= ~ARMV8_PMCR_MASK;
+		val |= p->regval & ARMV8_PMCR_MASK;
+		vcpu_sys_reg(vcpu, r->reg) = val;
+	} else {
+		/* PMCR.P & PMCR.C are RAZ */
+		val = vcpu_sys_reg(vcpu, r->reg)
+		      & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
+		p->regval = val;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -622,7 +657,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	/* PMCR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmcr, reset_pmcr, PMCR_EL0, },
 	/* PMCNTENSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
 	  trap_raz_wi },
@@ -884,7 +919,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
 
 	/* PMU */
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-- 
2.0.4

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

* [PATCH v7 05/19] KVM: ARM64: Add access handler for PMSELR register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMSELR_EL0 is UNKNOWN, use reset_unknown for
its reset handler. When reading PMSELR, return the PMSELR.SEL field to
guest.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 9a06116..c21f91b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -473,6 +473,19 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			  const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+	} else {
+		/* return PMSELR.SEL field */
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -672,7 +685,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMSELR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
-	  trap_raz_wi },
+	  access_pmselr, reset_unknown, PMSELR_EL0 },
 	/* PMCEID0_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
 	  trap_raz_wi },
@@ -923,7 +936,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
-- 
2.0.4

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

* [PATCH v7 05/19] KVM: ARM64: Add access handler for PMSELR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMSELR_EL0 is UNKNOWN, use reset_unknown for
its reset handler. When reading PMSELR, return the PMSELR.SEL field to
guest.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 9a06116..c21f91b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -473,6 +473,19 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			  const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+	} else {
+		/* return PMSELR.SEL field */
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -672,7 +685,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMSELR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
-	  trap_raz_wi },
+	  access_pmselr, reset_unknown, PMSELR_EL0 },
 	/* PMCEID0_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
 	  trap_raz_wi },
@@ -923,7 +936,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
-- 
2.0.4

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

* [PATCH v7 05/19] KVM: ARM64: Add access handler for PMSELR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMSELR_EL0 is UNKNOWN, use reset_unknown for
its reset handler. When reading PMSELR, return the PMSELR.SEL field to
guest.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 9a06116..c21f91b 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -473,6 +473,19 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			  const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		vcpu_sys_reg(vcpu, r->reg) = p->regval;
+	} else {
+		/* return PMSELR.SEL field */
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -672,7 +685,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMSELR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
-	  trap_raz_wi },
+	  access_pmselr, reset_unknown, PMSELR_EL0 },
 	/* PMCEID0_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
 	  trap_raz_wi },
@@ -923,7 +936,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
-- 
2.0.4

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

* [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Add access handler which gets host value of PMCEID0 or PMCEID1 when
guest access these registers. Writing action to PMCEID0 or PMCEID1 is
ignored.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c21f91b..e043224 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -486,6 +486,24 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			  const struct sys_reg_desc *r)
+{
+	u64 pmceid;
+
+	if (p->is_write)
+		return write_to_read_only(vcpu, p);
+
+	if (!(p->Op2 & 1))
+		asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
+	else
+		asm volatile("mrs %0, pmceid1_el0\n" : "=r" (pmceid));
+
+	p->regval = pmceid;
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -688,10 +706,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmselr, reset_unknown, PMSELR_EL0 },
 	/* PMCEID0_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
-	  trap_raz_wi },
+	  access_pmceid },
 	/* PMCEID1_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
-	  trap_raz_wi },
+	  access_pmceid },
 	/* PMCCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
 	  trap_raz_wi },
@@ -937,8 +955,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
-- 
2.0.4

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

* [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Add access handler which gets host value of PMCEID0 or PMCEID1 when
guest access these registers. Writing action to PMCEID0 or PMCEID1 is
ignored.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c21f91b..e043224 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -486,6 +486,24 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			  const struct sys_reg_desc *r)
+{
+	u64 pmceid;
+
+	if (p->is_write)
+		return write_to_read_only(vcpu, p);
+
+	if (!(p->Op2 & 1))
+		asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
+	else
+		asm volatile("mrs %0, pmceid1_el0\n" : "=r" (pmceid));
+
+	p->regval = pmceid;
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -688,10 +706,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmselr, reset_unknown, PMSELR_EL0 },
 	/* PMCEID0_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
-	  trap_raz_wi },
+	  access_pmceid },
 	/* PMCEID1_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
-	  trap_raz_wi },
+	  access_pmceid },
 	/* PMCCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
 	  trap_raz_wi },
@@ -937,8 +955,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
-- 
2.0.4

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

* [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Add access handler which gets host value of PMCEID0 or PMCEID1 when
guest access these registers. Writing action to PMCEID0 or PMCEID1 is
ignored.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c21f91b..e043224 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -486,6 +486,24 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			  const struct sys_reg_desc *r)
+{
+	u64 pmceid;
+
+	if (p->is_write)
+		return write_to_read_only(vcpu, p);
+
+	if (!(p->Op2 & 1))
+		asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
+	else
+		asm volatile("mrs %0, pmceid1_el0\n" : "=r" (pmceid));
+
+	p->regval = pmceid;
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -688,10 +706,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmselr, reset_unknown, PMSELR_EL0 },
 	/* PMCEID0_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
-	  trap_raz_wi },
+	  access_pmceid },
 	/* PMCEID1_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
-	  trap_raz_wi },
+	  access_pmceid },
 	/* PMCCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
 	  trap_raz_wi },
@@ -937,8 +955,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
-- 
2.0.4

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

* [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

When we use tools like perf on host, perf passes the event type and the
id of this event type category to kernel, then kernel will map them to
hardware event number and write this number to PMU PMEVTYPER<n>_EL0
register. When getting the event number in KVM, directly use raw event
type to create a perf_event for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/pmu.h |   3 ++
 arch/arm64/kvm/Makefile      |   1 +
 include/kvm/arm_pmu.h        |  11 ++++
 virt/kvm/arm/pmu.c           | 122 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 137 insertions(+)
 create mode 100644 virt/kvm/arm/pmu.c

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
index 4264ea0..714edcc 100644
--- a/arch/arm64/include/asm/pmu.h
+++ b/arch/arm64/include/asm/pmu.h
@@ -18,6 +18,7 @@
 
 #define ARMV8_MAX_COUNTERS      32
 #define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
+#define ARMV8_CYCLE_IDX         (ARMV8_MAX_COUNTERS - 1)
 
 /*
  * Per-CPU PMCR: config reg
@@ -28,6 +29,8 @@
 #define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
 #define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
 #define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+/* Determines which PMCCNTR_EL0 bit generates an overflow */
+#define ARMV8_PMCR_LC		(1 << 6)
 #define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
 #define	ARMV8_PMCR_N_MASK	0x1f
 #define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 1949fe5..18d56d8 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -27,3 +27,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
+kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index ddcb5b2..14bedb0 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -34,9 +34,20 @@ struct kvm_pmu {
 	int irq_num;
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx);
 #else
 struct kvm_pmu {
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+	return 0;
+}
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
new file mode 100644
index 0000000..b107fb8
--- /dev/null
+++ b/virt/kvm/arm/pmu.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao <shannon.zhao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include <asm/kvm_emulate.h>
+#include <kvm/arm_pmu.h>
+
+/**
+ * kvm_pmu_get_counter_value - get PMU counter value
+ * @vcpu: The vcpu pointer
+ * @select_idx: The counter index
+ */
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+	u64 counter, reg, enabled, running;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+
+	reg = (select_idx == ARMV8_CYCLE_IDX)
+	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
+	counter = vcpu_sys_reg(vcpu, reg);
+
+	/* The real counter value is equal to the value of counter register plus
+	 * the value perf event counts.
+	 */
+	if (pmc->perf_event)
+		counter += perf_event_read_value(pmc->perf_event, &enabled,
+						 &running);
+
+	return counter & pmc->bitmask;
+}
+
+static inline bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu,
+					      u64 select_idx)
+{
+	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &&
+	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
+}
+
+/**
+ * kvm_pmu_stop_counter - stop PMU counter
+ * @pmc: The PMU counter pointer
+ *
+ * If this counter has been configured to monitor some event, release it here.
+ */
+static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
+{
+	u64 counter, reg;
+
+	if (pmc->perf_event) {
+		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
+		reg = (pmc->idx == ARMV8_CYCLE_IDX)
+		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
+		vcpu_sys_reg(vcpu, reg) = counter;
+		perf_event_release_kernel(pmc->perf_event);
+		pmc->perf_event = NULL;
+	}
+}
+
+/**
+ * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
+ * @vcpu: The vcpu pointer
+ * @data: The data guest writes to PMXEVTYPER_EL0
+ * @select_idx: The number of selected counter
+ *
+ * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
+ * event with given hardware event number. Here we call perf_event API to
+ * emulate this action and create a kernel perf event for it.
+ */
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+	struct perf_event *event;
+	struct perf_event_attr attr;
+	u64 eventsel, counter;
+
+	kvm_pmu_stop_counter(vcpu, pmc);
+	eventsel = data & ARMV8_EVTYPE_EVENT;
+
+	memset(&attr, 0, sizeof(struct perf_event_attr));
+	attr.type = PERF_TYPE_RAW;
+	attr.size = sizeof(attr);
+	attr.pinned = 1;
+	attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
+	attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
+	attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
+	attr.exclude_hv = 1; /* Don't count EL2 events */
+	attr.exclude_host = 1; /* Don't count host events */
+	attr.config = eventsel;
+
+	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
+	/* The initial sample period (overflow count) of an event. */
+	attr.sample_period = (-counter) & pmc->bitmask;
+
+	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
+	if (IS_ERR(event)) {
+		printk_once("kvm: pmu event creation failed %ld\n",
+			    PTR_ERR(event));
+		return;
+	}
+
+	pmc->perf_event = event;
+}
-- 
2.0.4

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

* [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

When we use tools like perf on host, perf passes the event type and the
id of this event type category to kernel, then kernel will map them to
hardware event number and write this number to PMU PMEVTYPER<n>_EL0
register. When getting the event number in KVM, directly use raw event
type to create a perf_event for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/pmu.h |   3 ++
 arch/arm64/kvm/Makefile      |   1 +
 include/kvm/arm_pmu.h        |  11 ++++
 virt/kvm/arm/pmu.c           | 122 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 137 insertions(+)
 create mode 100644 virt/kvm/arm/pmu.c

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
index 4264ea0..714edcc 100644
--- a/arch/arm64/include/asm/pmu.h
+++ b/arch/arm64/include/asm/pmu.h
@@ -18,6 +18,7 @@
 
 #define ARMV8_MAX_COUNTERS      32
 #define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
+#define ARMV8_CYCLE_IDX         (ARMV8_MAX_COUNTERS - 1)
 
 /*
  * Per-CPU PMCR: config reg
@@ -28,6 +29,8 @@
 #define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
 #define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
 #define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+/* Determines which PMCCNTR_EL0 bit generates an overflow */
+#define ARMV8_PMCR_LC		(1 << 6)
 #define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
 #define	ARMV8_PMCR_N_MASK	0x1f
 #define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 1949fe5..18d56d8 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -27,3 +27,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
+kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index ddcb5b2..14bedb0 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -34,9 +34,20 @@ struct kvm_pmu {
 	int irq_num;
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx);
 #else
 struct kvm_pmu {
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+	return 0;
+}
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
new file mode 100644
index 0000000..b107fb8
--- /dev/null
+++ b/virt/kvm/arm/pmu.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao <shannon.zhao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include <asm/kvm_emulate.h>
+#include <kvm/arm_pmu.h>
+
+/**
+ * kvm_pmu_get_counter_value - get PMU counter value
+ * @vcpu: The vcpu pointer
+ * @select_idx: The counter index
+ */
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+	u64 counter, reg, enabled, running;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+
+	reg = (select_idx == ARMV8_CYCLE_IDX)
+	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
+	counter = vcpu_sys_reg(vcpu, reg);
+
+	/* The real counter value is equal to the value of counter register plus
+	 * the value perf event counts.
+	 */
+	if (pmc->perf_event)
+		counter += perf_event_read_value(pmc->perf_event, &enabled,
+						 &running);
+
+	return counter & pmc->bitmask;
+}
+
+static inline bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu,
+					      u64 select_idx)
+{
+	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &&
+	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
+}
+
+/**
+ * kvm_pmu_stop_counter - stop PMU counter
+ * @pmc: The PMU counter pointer
+ *
+ * If this counter has been configured to monitor some event, release it here.
+ */
+static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
+{
+	u64 counter, reg;
+
+	if (pmc->perf_event) {
+		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
+		reg = (pmc->idx == ARMV8_CYCLE_IDX)
+		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
+		vcpu_sys_reg(vcpu, reg) = counter;
+		perf_event_release_kernel(pmc->perf_event);
+		pmc->perf_event = NULL;
+	}
+}
+
+/**
+ * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
+ * @vcpu: The vcpu pointer
+ * @data: The data guest writes to PMXEVTYPER_EL0
+ * @select_idx: The number of selected counter
+ *
+ * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
+ * event with given hardware event number. Here we call perf_event API to
+ * emulate this action and create a kernel perf event for it.
+ */
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+	struct perf_event *event;
+	struct perf_event_attr attr;
+	u64 eventsel, counter;
+
+	kvm_pmu_stop_counter(vcpu, pmc);
+	eventsel = data & ARMV8_EVTYPE_EVENT;
+
+	memset(&attr, 0, sizeof(struct perf_event_attr));
+	attr.type = PERF_TYPE_RAW;
+	attr.size = sizeof(attr);
+	attr.pinned = 1;
+	attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
+	attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
+	attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
+	attr.exclude_hv = 1; /* Don't count EL2 events */
+	attr.exclude_host = 1; /* Don't count host events */
+	attr.config = eventsel;
+
+	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
+	/* The initial sample period (overflow count) of an event. */
+	attr.sample_period = (-counter) & pmc->bitmask;
+
+	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
+	if (IS_ERR(event)) {
+		printk_once("kvm: pmu event creation failed %ld\n",
+			    PTR_ERR(event));
+		return;
+	}
+
+	pmc->perf_event = event;
+}
-- 
2.0.4

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

* [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

When we use tools like perf on host, perf passes the event type and the
id of this event type category to kernel, then kernel will map them to
hardware event number and write this number to PMU PMEVTYPER<n>_EL0
register. When getting the event number in KVM, directly use raw event
type to create a perf_event for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/include/asm/pmu.h |   3 ++
 arch/arm64/kvm/Makefile      |   1 +
 include/kvm/arm_pmu.h        |  11 ++++
 virt/kvm/arm/pmu.c           | 122 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 137 insertions(+)
 create mode 100644 virt/kvm/arm/pmu.c

diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
index 4264ea0..714edcc 100644
--- a/arch/arm64/include/asm/pmu.h
+++ b/arch/arm64/include/asm/pmu.h
@@ -18,6 +18,7 @@
 
 #define ARMV8_MAX_COUNTERS      32
 #define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
+#define ARMV8_CYCLE_IDX         (ARMV8_MAX_COUNTERS - 1)
 
 /*
  * Per-CPU PMCR: config reg
@@ -28,6 +29,8 @@
 #define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
 #define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
 #define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
+/* Determines which PMCCNTR_EL0 bit generates an overflow */
+#define ARMV8_PMCR_LC		(1 << 6)
 #define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
 #define	ARMV8_PMCR_N_MASK	0x1f
 #define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 1949fe5..18d56d8 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -27,3 +27,4 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
 kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
+kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index ddcb5b2..14bedb0 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -34,9 +34,20 @@ struct kvm_pmu {
 	int irq_num;
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx);
 #else
 struct kvm_pmu {
 };
+
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+	return 0;
+}
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
new file mode 100644
index 0000000..b107fb8
--- /dev/null
+++ b/virt/kvm/arm/pmu.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd.
+ * Author: Shannon Zhao <shannon.zhao@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/perf_event.h>
+#include <asm/kvm_emulate.h>
+#include <kvm/arm_pmu.h>
+
+/**
+ * kvm_pmu_get_counter_value - get PMU counter value
+ * @vcpu: The vcpu pointer
+ * @select_idx: The counter index
+ */
+u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
+{
+	u64 counter, reg, enabled, running;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+
+	reg = (select_idx == ARMV8_CYCLE_IDX)
+	      ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + select_idx;
+	counter = vcpu_sys_reg(vcpu, reg);
+
+	/* The real counter value is equal to the value of counter register plus
+	 * the value perf event counts.
+	 */
+	if (pmc->perf_event)
+		counter += perf_event_read_value(pmc->perf_event, &enabled,
+						 &running);
+
+	return counter & pmc->bitmask;
+}
+
+static inline bool kvm_pmu_counter_is_enabled(struct kvm_vcpu *vcpu,
+					      u64 select_idx)
+{
+	return (vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) &&
+	       (vcpu_sys_reg(vcpu, PMCNTENSET_EL0) & BIT(select_idx));
+}
+
+/**
+ * kvm_pmu_stop_counter - stop PMU counter
+ * @pmc: The PMU counter pointer
+ *
+ * If this counter has been configured to monitor some event, release it here.
+ */
+static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
+{
+	u64 counter, reg;
+
+	if (pmc->perf_event) {
+		counter = kvm_pmu_get_counter_value(vcpu, pmc->idx);
+		reg = (pmc->idx == ARMV8_CYCLE_IDX)
+		       ? PMCCNTR_EL0 : PMEVCNTR0_EL0 + pmc->idx;
+		vcpu_sys_reg(vcpu, reg) = counter;
+		perf_event_release_kernel(pmc->perf_event);
+		pmc->perf_event = NULL;
+	}
+}
+
+/**
+ * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
+ * @vcpu: The vcpu pointer
+ * @data: The data guest writes to PMXEVTYPER_EL0
+ * @select_idx: The number of selected counter
+ *
+ * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
+ * event with given hardware event number. Here we call perf_event API to
+ * emulate this action and create a kernel perf event for it.
+ */
+void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
+				    u64 select_idx)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
+	struct perf_event *event;
+	struct perf_event_attr attr;
+	u64 eventsel, counter;
+
+	kvm_pmu_stop_counter(vcpu, pmc);
+	eventsel = data & ARMV8_EVTYPE_EVENT;
+
+	memset(&attr, 0, sizeof(struct perf_event_attr));
+	attr.type = PERF_TYPE_RAW;
+	attr.size = sizeof(attr);
+	attr.pinned = 1;
+	attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
+	attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
+	attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
+	attr.exclude_hv = 1; /* Don't count EL2 events */
+	attr.exclude_host = 1; /* Don't count host events */
+	attr.config = eventsel;
+
+	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
+	/* The initial sample period (overflow count) of an event. */
+	attr.sample_period = (-counter) & pmc->bitmask;
+
+	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
+	if (IS_ERR(event)) {
+		printk_once("kvm: pmu event creation failed %ld\n",
+			    PTR_ERR(event));
+		return;
+	}
+
+	pmc->perf_event = event;
+}
-- 
2.0.4

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

* [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
which is mapped to PMEVTYPERn or PMCCFILTR.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When writing to these registers, create a perf_event for the selected
event type.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 152 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index e043224..c52ff15 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
+{
+	u64 pmcr, val;
+
+	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
+	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
+	if (idx >= val && idx != ARMV8_CYCLE_IDX)
+		return false;
+
+	return true;
+}
+
+static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			       const struct sys_reg_desc *r)
+{
+	u64 idx, reg;
+
+	if (r->CRn == 9) {
+		/* PMXEVTYPER_EL0 */
+		reg = 0;
+	} else {
+		if (!p->is_aarch32) {
+			/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
+			reg = r->reg;
+		} else {
+			if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
+				reg = PMCCFILTR_EL0;
+			} else {
+				reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+				reg += PMEVTYPER0_EL0;
+			}
+		}
+	}
+
+	switch (reg) {
+	case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
+		idx = reg - PMEVTYPER0_EL0;
+		break;
+	case PMCCFILTR_EL0:
+		idx = ARMV8_CYCLE_IDX;
+		break;
+	default:
+		/* PMXEVTYPER_EL0 */
+		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return true;
+
+		reg = (idx == ARMV8_CYCLE_IDX) ? PMCCFILTR_EL0
+						 : PMEVTYPER0_EL0 + idx;
+		break;
+	}
+
+	if (p->is_write) {
+		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
+		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -519,6 +581,13 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111),	\
 	  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVTYPERn_EL0 register */
+#define PMU_PMEVTYPER_EL0(n)						\
+	/* PMEVTYPERn_EL0 */						\
+	{ Op0(0b11), Op1(0b011), CRn(0b1110),				\
+	  CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -715,7 +784,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMXEVTYPER_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmu_evtyper },
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
 	  trap_raz_wi },
@@ -733,6 +802,45 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
 	  NULL, reset_unknown, TPIDRRO_EL0 },
 
+	/* PMEVTYPERn_EL0 */
+	PMU_PMEVTYPER_EL0(0),
+	PMU_PMEVTYPER_EL0(1),
+	PMU_PMEVTYPER_EL0(2),
+	PMU_PMEVTYPER_EL0(3),
+	PMU_PMEVTYPER_EL0(4),
+	PMU_PMEVTYPER_EL0(5),
+	PMU_PMEVTYPER_EL0(6),
+	PMU_PMEVTYPER_EL0(7),
+	PMU_PMEVTYPER_EL0(8),
+	PMU_PMEVTYPER_EL0(9),
+	PMU_PMEVTYPER_EL0(10),
+	PMU_PMEVTYPER_EL0(11),
+	PMU_PMEVTYPER_EL0(12),
+	PMU_PMEVTYPER_EL0(13),
+	PMU_PMEVTYPER_EL0(14),
+	PMU_PMEVTYPER_EL0(15),
+	PMU_PMEVTYPER_EL0(16),
+	PMU_PMEVTYPER_EL0(17),
+	PMU_PMEVTYPER_EL0(18),
+	PMU_PMEVTYPER_EL0(19),
+	PMU_PMEVTYPER_EL0(20),
+	PMU_PMEVTYPER_EL0(21),
+	PMU_PMEVTYPER_EL0(22),
+	PMU_PMEVTYPER_EL0(23),
+	PMU_PMEVTYPER_EL0(24),
+	PMU_PMEVTYPER_EL0(25),
+	PMU_PMEVTYPER_EL0(26),
+	PMU_PMEVTYPER_EL0(27),
+	PMU_PMEVTYPER_EL0(28),
+	PMU_PMEVTYPER_EL0(29),
+	PMU_PMEVTYPER_EL0(30),
+	/* PMCCFILTR_EL0
+	 * This register resets as unknown in 64bit mode while it resets as zero
+	 * in 32bit mode. Here we choose to reset it as zero for consistency.
+	 */
+	{ Op0(0b11), Op1(0b011), CRn(0b1110), CRm(0b1111), Op2(0b111),
+	  access_pmu_evtyper, reset_val, PMCCFILTR_EL0, 0 },
+
 	/* DACR32_EL2 */
 	{ Op0(0b11), Op1(0b100), CRn(0b0011), CRm(0b0000), Op2(0b000),
 	  NULL, reset_unknown, DACR32_EL2 },
@@ -922,6 +1030,13 @@ static const struct sys_reg_desc cp14_64_regs[] = {
 	{ Op1( 0), CRm( 2), .access = trap_raz_wi },
 };
 
+/* Macro to expand the PMEVTYPERn register */
+#define PMU_PMEVTYPER(n)						\
+	/* PMEVTYPERn */						\
+	{ Op1(0), CRn(0b1110),						\
+	  CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evtyper }
+
 /*
  * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
  * depending on the way they are accessed (as a 32bit or a 64bit
@@ -958,7 +1073,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
@@ -973,6 +1088,41 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn(12), CRm(12), Op2( 5), trap_raz_wi },
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
+
+	/* PMEVTYPERn */
+	PMU_PMEVTYPER(0),
+	PMU_PMEVTYPER(1),
+	PMU_PMEVTYPER(2),
+	PMU_PMEVTYPER(3),
+	PMU_PMEVTYPER(4),
+	PMU_PMEVTYPER(5),
+	PMU_PMEVTYPER(6),
+	PMU_PMEVTYPER(7),
+	PMU_PMEVTYPER(8),
+	PMU_PMEVTYPER(9),
+	PMU_PMEVTYPER(10),
+	PMU_PMEVTYPER(11),
+	PMU_PMEVTYPER(12),
+	PMU_PMEVTYPER(13),
+	PMU_PMEVTYPER(14),
+	PMU_PMEVTYPER(15),
+	PMU_PMEVTYPER(16),
+	PMU_PMEVTYPER(17),
+	PMU_PMEVTYPER(18),
+	PMU_PMEVTYPER(19),
+	PMU_PMEVTYPER(20),
+	PMU_PMEVTYPER(21),
+	PMU_PMEVTYPER(22),
+	PMU_PMEVTYPER(23),
+	PMU_PMEVTYPER(24),
+	PMU_PMEVTYPER(25),
+	PMU_PMEVTYPER(26),
+	PMU_PMEVTYPER(27),
+	PMU_PMEVTYPER(28),
+	PMU_PMEVTYPER(29),
+	PMU_PMEVTYPER(30),
+	/* PMCCFILTR */
+	{ Op1(0), CRn(14), CRm(15), Op2(7), access_pmu_evtyper },
 };
 
 static const struct sys_reg_desc cp15_64_regs[] = {
-- 
2.0.4

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

* [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
which is mapped to PMEVTYPERn or PMCCFILTR.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When writing to these registers, create a perf_event for the selected
event type.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 152 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index e043224..c52ff15 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
+{
+	u64 pmcr, val;
+
+	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
+	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
+	if (idx >= val && idx != ARMV8_CYCLE_IDX)
+		return false;
+
+	return true;
+}
+
+static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			       const struct sys_reg_desc *r)
+{
+	u64 idx, reg;
+
+	if (r->CRn == 9) {
+		/* PMXEVTYPER_EL0 */
+		reg = 0;
+	} else {
+		if (!p->is_aarch32) {
+			/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
+			reg = r->reg;
+		} else {
+			if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
+				reg = PMCCFILTR_EL0;
+			} else {
+				reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+				reg += PMEVTYPER0_EL0;
+			}
+		}
+	}
+
+	switch (reg) {
+	case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
+		idx = reg - PMEVTYPER0_EL0;
+		break;
+	case PMCCFILTR_EL0:
+		idx = ARMV8_CYCLE_IDX;
+		break;
+	default:
+		/* PMXEVTYPER_EL0 */
+		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return true;
+
+		reg = (idx == ARMV8_CYCLE_IDX) ? PMCCFILTR_EL0
+						 : PMEVTYPER0_EL0 + idx;
+		break;
+	}
+
+	if (p->is_write) {
+		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
+		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -519,6 +581,13 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111),	\
 	  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVTYPERn_EL0 register */
+#define PMU_PMEVTYPER_EL0(n)						\
+	/* PMEVTYPERn_EL0 */						\
+	{ Op0(0b11), Op1(0b011), CRn(0b1110),				\
+	  CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -715,7 +784,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMXEVTYPER_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmu_evtyper },
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
 	  trap_raz_wi },
@@ -733,6 +802,45 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
 	  NULL, reset_unknown, TPIDRRO_EL0 },
 
+	/* PMEVTYPERn_EL0 */
+	PMU_PMEVTYPER_EL0(0),
+	PMU_PMEVTYPER_EL0(1),
+	PMU_PMEVTYPER_EL0(2),
+	PMU_PMEVTYPER_EL0(3),
+	PMU_PMEVTYPER_EL0(4),
+	PMU_PMEVTYPER_EL0(5),
+	PMU_PMEVTYPER_EL0(6),
+	PMU_PMEVTYPER_EL0(7),
+	PMU_PMEVTYPER_EL0(8),
+	PMU_PMEVTYPER_EL0(9),
+	PMU_PMEVTYPER_EL0(10),
+	PMU_PMEVTYPER_EL0(11),
+	PMU_PMEVTYPER_EL0(12),
+	PMU_PMEVTYPER_EL0(13),
+	PMU_PMEVTYPER_EL0(14),
+	PMU_PMEVTYPER_EL0(15),
+	PMU_PMEVTYPER_EL0(16),
+	PMU_PMEVTYPER_EL0(17),
+	PMU_PMEVTYPER_EL0(18),
+	PMU_PMEVTYPER_EL0(19),
+	PMU_PMEVTYPER_EL0(20),
+	PMU_PMEVTYPER_EL0(21),
+	PMU_PMEVTYPER_EL0(22),
+	PMU_PMEVTYPER_EL0(23),
+	PMU_PMEVTYPER_EL0(24),
+	PMU_PMEVTYPER_EL0(25),
+	PMU_PMEVTYPER_EL0(26),
+	PMU_PMEVTYPER_EL0(27),
+	PMU_PMEVTYPER_EL0(28),
+	PMU_PMEVTYPER_EL0(29),
+	PMU_PMEVTYPER_EL0(30),
+	/* PMCCFILTR_EL0
+	 * This register resets as unknown in 64bit mode while it resets as zero
+	 * in 32bit mode. Here we choose to reset it as zero for consistency.
+	 */
+	{ Op0(0b11), Op1(0b011), CRn(0b1110), CRm(0b1111), Op2(0b111),
+	  access_pmu_evtyper, reset_val, PMCCFILTR_EL0, 0 },
+
 	/* DACR32_EL2 */
 	{ Op0(0b11), Op1(0b100), CRn(0b0011), CRm(0b0000), Op2(0b000),
 	  NULL, reset_unknown, DACR32_EL2 },
@@ -922,6 +1030,13 @@ static const struct sys_reg_desc cp14_64_regs[] = {
 	{ Op1( 0), CRm( 2), .access = trap_raz_wi },
 };
 
+/* Macro to expand the PMEVTYPERn register */
+#define PMU_PMEVTYPER(n)						\
+	/* PMEVTYPERn */						\
+	{ Op1(0), CRn(0b1110),						\
+	  CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evtyper }
+
 /*
  * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
  * depending on the way they are accessed (as a 32bit or a 64bit
@@ -958,7 +1073,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
@@ -973,6 +1088,41 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn(12), CRm(12), Op2( 5), trap_raz_wi },
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
+
+	/* PMEVTYPERn */
+	PMU_PMEVTYPER(0),
+	PMU_PMEVTYPER(1),
+	PMU_PMEVTYPER(2),
+	PMU_PMEVTYPER(3),
+	PMU_PMEVTYPER(4),
+	PMU_PMEVTYPER(5),
+	PMU_PMEVTYPER(6),
+	PMU_PMEVTYPER(7),
+	PMU_PMEVTYPER(8),
+	PMU_PMEVTYPER(9),
+	PMU_PMEVTYPER(10),
+	PMU_PMEVTYPER(11),
+	PMU_PMEVTYPER(12),
+	PMU_PMEVTYPER(13),
+	PMU_PMEVTYPER(14),
+	PMU_PMEVTYPER(15),
+	PMU_PMEVTYPER(16),
+	PMU_PMEVTYPER(17),
+	PMU_PMEVTYPER(18),
+	PMU_PMEVTYPER(19),
+	PMU_PMEVTYPER(20),
+	PMU_PMEVTYPER(21),
+	PMU_PMEVTYPER(22),
+	PMU_PMEVTYPER(23),
+	PMU_PMEVTYPER(24),
+	PMU_PMEVTYPER(25),
+	PMU_PMEVTYPER(26),
+	PMU_PMEVTYPER(27),
+	PMU_PMEVTYPER(28),
+	PMU_PMEVTYPER(29),
+	PMU_PMEVTYPER(30),
+	/* PMCCFILTR */
+	{ Op1(0), CRn(14), CRm(15), Op2(7), access_pmu_evtyper },
 };
 
 static const struct sys_reg_desc cp15_64_regs[] = {
-- 
2.0.4

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

* [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
which is mapped to PMEVTYPERn or PMCCFILTR.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When writing to these registers, create a perf_event for the selected
event type.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 152 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index e043224..c52ff15 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
+{
+	u64 pmcr, val;
+
+	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
+	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
+	if (idx >= val && idx != ARMV8_CYCLE_IDX)
+		return false;
+
+	return true;
+}
+
+static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			       const struct sys_reg_desc *r)
+{
+	u64 idx, reg;
+
+	if (r->CRn == 9) {
+		/* PMXEVTYPER_EL0 */
+		reg = 0;
+	} else {
+		if (!p->is_aarch32) {
+			/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
+			reg = r->reg;
+		} else {
+			if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
+				reg = PMCCFILTR_EL0;
+			} else {
+				reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+				reg += PMEVTYPER0_EL0;
+			}
+		}
+	}
+
+	switch (reg) {
+	case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
+		idx = reg - PMEVTYPER0_EL0;
+		break;
+	case PMCCFILTR_EL0:
+		idx = ARMV8_CYCLE_IDX;
+		break;
+	default:
+		/* PMXEVTYPER_EL0 */
+		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return true;
+
+		reg = (idx == ARMV8_CYCLE_IDX) ? PMCCFILTR_EL0
+						 : PMEVTYPER0_EL0 + idx;
+		break;
+	}
+
+	if (p->is_write) {
+		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
+		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -519,6 +581,13 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111),	\
 	  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVTYPERn_EL0 register */
+#define PMU_PMEVTYPER_EL0(n)						\
+	/* PMEVTYPERn_EL0 */						\
+	{ Op0(0b11), Op1(0b011), CRn(0b1110),				\
+	  CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
+
 /*
  * Architected system registers.
  * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -715,7 +784,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMXEVTYPER_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmu_evtyper },
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
 	  trap_raz_wi },
@@ -733,6 +802,45 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
 	  NULL, reset_unknown, TPIDRRO_EL0 },
 
+	/* PMEVTYPERn_EL0 */
+	PMU_PMEVTYPER_EL0(0),
+	PMU_PMEVTYPER_EL0(1),
+	PMU_PMEVTYPER_EL0(2),
+	PMU_PMEVTYPER_EL0(3),
+	PMU_PMEVTYPER_EL0(4),
+	PMU_PMEVTYPER_EL0(5),
+	PMU_PMEVTYPER_EL0(6),
+	PMU_PMEVTYPER_EL0(7),
+	PMU_PMEVTYPER_EL0(8),
+	PMU_PMEVTYPER_EL0(9),
+	PMU_PMEVTYPER_EL0(10),
+	PMU_PMEVTYPER_EL0(11),
+	PMU_PMEVTYPER_EL0(12),
+	PMU_PMEVTYPER_EL0(13),
+	PMU_PMEVTYPER_EL0(14),
+	PMU_PMEVTYPER_EL0(15),
+	PMU_PMEVTYPER_EL0(16),
+	PMU_PMEVTYPER_EL0(17),
+	PMU_PMEVTYPER_EL0(18),
+	PMU_PMEVTYPER_EL0(19),
+	PMU_PMEVTYPER_EL0(20),
+	PMU_PMEVTYPER_EL0(21),
+	PMU_PMEVTYPER_EL0(22),
+	PMU_PMEVTYPER_EL0(23),
+	PMU_PMEVTYPER_EL0(24),
+	PMU_PMEVTYPER_EL0(25),
+	PMU_PMEVTYPER_EL0(26),
+	PMU_PMEVTYPER_EL0(27),
+	PMU_PMEVTYPER_EL0(28),
+	PMU_PMEVTYPER_EL0(29),
+	PMU_PMEVTYPER_EL0(30),
+	/* PMCCFILTR_EL0
+	 * This register resets as unknown in 64bit mode while it resets as zero
+	 * in 32bit mode. Here we choose to reset it as zero for consistency.
+	 */
+	{ Op0(0b11), Op1(0b011), CRn(0b1110), CRm(0b1111), Op2(0b111),
+	  access_pmu_evtyper, reset_val, PMCCFILTR_EL0, 0 },
+
 	/* DACR32_EL2 */
 	{ Op0(0b11), Op1(0b100), CRn(0b0011), CRm(0b0000), Op2(0b000),
 	  NULL, reset_unknown, DACR32_EL2 },
@@ -922,6 +1030,13 @@ static const struct sys_reg_desc cp14_64_regs[] = {
 	{ Op1( 0), CRm( 2), .access = trap_raz_wi },
 };
 
+/* Macro to expand the PMEVTYPERn register */
+#define PMU_PMEVTYPER(n)						\
+	/* PMEVTYPERn */						\
+	{ Op1(0), CRn(0b1110),						\
+	  CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evtyper }
+
 /*
  * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding,
  * depending on the way they are accessed (as a 32bit or a 64bit
@@ -958,7 +1073,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
@@ -973,6 +1088,41 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn(12), CRm(12), Op2( 5), trap_raz_wi },
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
+
+	/* PMEVTYPERn */
+	PMU_PMEVTYPER(0),
+	PMU_PMEVTYPER(1),
+	PMU_PMEVTYPER(2),
+	PMU_PMEVTYPER(3),
+	PMU_PMEVTYPER(4),
+	PMU_PMEVTYPER(5),
+	PMU_PMEVTYPER(6),
+	PMU_PMEVTYPER(7),
+	PMU_PMEVTYPER(8),
+	PMU_PMEVTYPER(9),
+	PMU_PMEVTYPER(10),
+	PMU_PMEVTYPER(11),
+	PMU_PMEVTYPER(12),
+	PMU_PMEVTYPER(13),
+	PMU_PMEVTYPER(14),
+	PMU_PMEVTYPER(15),
+	PMU_PMEVTYPER(16),
+	PMU_PMEVTYPER(17),
+	PMU_PMEVTYPER(18),
+	PMU_PMEVTYPER(19),
+	PMU_PMEVTYPER(20),
+	PMU_PMEVTYPER(21),
+	PMU_PMEVTYPER(22),
+	PMU_PMEVTYPER(23),
+	PMU_PMEVTYPER(24),
+	PMU_PMEVTYPER(25),
+	PMU_PMEVTYPER(26),
+	PMU_PMEVTYPER(27),
+	PMU_PMEVTYPER(28),
+	PMU_PMEVTYPER(29),
+	PMU_PMEVTYPER(30),
+	/* PMCCFILTR */
+	{ Op1(0), CRn(14), CRm(15), Op2(7), access_pmu_evtyper },
 };
 
 static const struct sys_reg_desc cp15_64_regs[] = {
-- 
2.0.4

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

* [PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
is mapped to PMEVCNTRn.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When reading these registers, return the sum of register value and the
value perf event counts.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 136 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 132 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c52ff15..dc6bb26 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -566,6 +566,55 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
+			      struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 idx, reg, val;
+
+	if (!p->is_aarch32) {
+		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
+			/* PMXEVCNTR_EL0 */
+			reg = 0;
+		else
+			/* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
+			reg = r->reg;
+	} else {
+		if (r->CRn == 9 && r->CRm == 13) {
+			reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
+		} else {
+			reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+			reg += PMEVCNTR0_EL0;
+		}
+	}
+
+	switch (reg) {
+	case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+		idx = reg - PMEVCNTR0_EL0;
+		break;
+	case PMCCNTR_EL0:
+		idx = ARMV8_CYCLE_IDX;
+		break;
+	default:
+		/* PMXEVCNTR_EL0 */
+		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return true;
+
+		reg = (idx == ARMV8_CYCLE_IDX) ? PMCCNTR_EL0
+						 : PMEVCNTR0_EL0 + idx;
+		break;
+	}
+
+	val = kvm_pmu_get_counter_value(vcpu, idx);
+	if (p->is_write)
+		vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
+	else
+		p->regval = val;
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -581,6 +630,13 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111),	\
 	  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVCNTRn_EL0 register */
+#define PMU_PMEVCNTR_EL0(n)						\
+	/* PMEVCNTRn_EL0 */						\
+	{ Op0(0b11), Op1(0b011), CRn(0b1110),				\
+	  CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evcntr, reset_unknown, (PMEVCNTR0_EL0 + n), }
+
 /* Macro to expand the PMEVTYPERn_EL0 register */
 #define PMU_PMEVTYPER_EL0(n)						\
 	/* PMEVTYPERn_EL0 */						\
@@ -781,13 +837,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmceid },
 	/* PMCCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmu_evcntr, reset_unknown, PMCCNTR_EL0 },
 	/* PMXEVTYPER_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
 	  access_pmu_evtyper },
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmu_evcntr },
 	/* PMUSERENR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
 	  trap_raz_wi },
@@ -802,6 +858,38 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
 	  NULL, reset_unknown, TPIDRRO_EL0 },
 
+	/* PMEVCNTRn_EL0 */
+	PMU_PMEVCNTR_EL0(0),
+	PMU_PMEVCNTR_EL0(1),
+	PMU_PMEVCNTR_EL0(2),
+	PMU_PMEVCNTR_EL0(3),
+	PMU_PMEVCNTR_EL0(4),
+	PMU_PMEVCNTR_EL0(5),
+	PMU_PMEVCNTR_EL0(6),
+	PMU_PMEVCNTR_EL0(7),
+	PMU_PMEVCNTR_EL0(8),
+	PMU_PMEVCNTR_EL0(9),
+	PMU_PMEVCNTR_EL0(10),
+	PMU_PMEVCNTR_EL0(11),
+	PMU_PMEVCNTR_EL0(12),
+	PMU_PMEVCNTR_EL0(13),
+	PMU_PMEVCNTR_EL0(14),
+	PMU_PMEVCNTR_EL0(15),
+	PMU_PMEVCNTR_EL0(16),
+	PMU_PMEVCNTR_EL0(17),
+	PMU_PMEVCNTR_EL0(18),
+	PMU_PMEVCNTR_EL0(19),
+	PMU_PMEVCNTR_EL0(20),
+	PMU_PMEVCNTR_EL0(21),
+	PMU_PMEVCNTR_EL0(22),
+	PMU_PMEVCNTR_EL0(23),
+	PMU_PMEVCNTR_EL0(24),
+	PMU_PMEVCNTR_EL0(25),
+	PMU_PMEVCNTR_EL0(26),
+	PMU_PMEVCNTR_EL0(27),
+	PMU_PMEVCNTR_EL0(28),
+	PMU_PMEVCNTR_EL0(29),
+	PMU_PMEVCNTR_EL0(30),
 	/* PMEVTYPERn_EL0 */
 	PMU_PMEVTYPER_EL0(0),
 	PMU_PMEVTYPER_EL0(1),
@@ -1030,6 +1118,13 @@ static const struct sys_reg_desc cp14_64_regs[] = {
 	{ Op1( 0), CRm( 2), .access = trap_raz_wi },
 };
 
+/* Macro to expand the PMEVCNTRn register */
+#define PMU_PMEVCNTR(n)							\
+	/* PMEVCNTRn */							\
+	{ Op1(0), CRn(0b1110),						\
+	  CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evcntr }
+
 /* Macro to expand the PMEVTYPERn register */
 #define PMU_PMEVTYPER(n)						\
 	/* PMEVTYPERn */						\
@@ -1072,9 +1167,9 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
@@ -1089,6 +1184,38 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
 
+	/* PMEVCNTRn */
+	PMU_PMEVCNTR(0),
+	PMU_PMEVCNTR(1),
+	PMU_PMEVCNTR(2),
+	PMU_PMEVCNTR(3),
+	PMU_PMEVCNTR(4),
+	PMU_PMEVCNTR(5),
+	PMU_PMEVCNTR(6),
+	PMU_PMEVCNTR(7),
+	PMU_PMEVCNTR(8),
+	PMU_PMEVCNTR(9),
+	PMU_PMEVCNTR(10),
+	PMU_PMEVCNTR(11),
+	PMU_PMEVCNTR(12),
+	PMU_PMEVCNTR(13),
+	PMU_PMEVCNTR(14),
+	PMU_PMEVCNTR(15),
+	PMU_PMEVCNTR(16),
+	PMU_PMEVCNTR(17),
+	PMU_PMEVCNTR(18),
+	PMU_PMEVCNTR(19),
+	PMU_PMEVCNTR(20),
+	PMU_PMEVCNTR(21),
+	PMU_PMEVCNTR(22),
+	PMU_PMEVCNTR(23),
+	PMU_PMEVCNTR(24),
+	PMU_PMEVCNTR(25),
+	PMU_PMEVCNTR(26),
+	PMU_PMEVCNTR(27),
+	PMU_PMEVCNTR(28),
+	PMU_PMEVCNTR(29),
+	PMU_PMEVCNTR(30),
 	/* PMEVTYPERn */
 	PMU_PMEVTYPER(0),
 	PMU_PMEVTYPER(1),
@@ -1127,6 +1254,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 static const struct sys_reg_desc cp15_64_regs[] = {
 	{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
+	{ Op1( 0), CRn( 0), CRm( 9), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi },
 	{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
 };
-- 
2.0.4

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

* [PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
is mapped to PMEVCNTRn.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When reading these registers, return the sum of register value and the
value perf event counts.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 136 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 132 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c52ff15..dc6bb26 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -566,6 +566,55 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
+			      struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 idx, reg, val;
+
+	if (!p->is_aarch32) {
+		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
+			/* PMXEVCNTR_EL0 */
+			reg = 0;
+		else
+			/* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
+			reg = r->reg;
+	} else {
+		if (r->CRn == 9 && r->CRm == 13) {
+			reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
+		} else {
+			reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+			reg += PMEVCNTR0_EL0;
+		}
+	}
+
+	switch (reg) {
+	case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+		idx = reg - PMEVCNTR0_EL0;
+		break;
+	case PMCCNTR_EL0:
+		idx = ARMV8_CYCLE_IDX;
+		break;
+	default:
+		/* PMXEVCNTR_EL0 */
+		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return true;
+
+		reg = (idx == ARMV8_CYCLE_IDX) ? PMCCNTR_EL0
+						 : PMEVCNTR0_EL0 + idx;
+		break;
+	}
+
+	val = kvm_pmu_get_counter_value(vcpu, idx);
+	if (p->is_write)
+		vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
+	else
+		p->regval = val;
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -581,6 +630,13 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111),	\
 	  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVCNTRn_EL0 register */
+#define PMU_PMEVCNTR_EL0(n)						\
+	/* PMEVCNTRn_EL0 */						\
+	{ Op0(0b11), Op1(0b011), CRn(0b1110),				\
+	  CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evcntr, reset_unknown, (PMEVCNTR0_EL0 + n), }
+
 /* Macro to expand the PMEVTYPERn_EL0 register */
 #define PMU_PMEVTYPER_EL0(n)						\
 	/* PMEVTYPERn_EL0 */						\
@@ -781,13 +837,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmceid },
 	/* PMCCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmu_evcntr, reset_unknown, PMCCNTR_EL0 },
 	/* PMXEVTYPER_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
 	  access_pmu_evtyper },
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmu_evcntr },
 	/* PMUSERENR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
 	  trap_raz_wi },
@@ -802,6 +858,38 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
 	  NULL, reset_unknown, TPIDRRO_EL0 },
 
+	/* PMEVCNTRn_EL0 */
+	PMU_PMEVCNTR_EL0(0),
+	PMU_PMEVCNTR_EL0(1),
+	PMU_PMEVCNTR_EL0(2),
+	PMU_PMEVCNTR_EL0(3),
+	PMU_PMEVCNTR_EL0(4),
+	PMU_PMEVCNTR_EL0(5),
+	PMU_PMEVCNTR_EL0(6),
+	PMU_PMEVCNTR_EL0(7),
+	PMU_PMEVCNTR_EL0(8),
+	PMU_PMEVCNTR_EL0(9),
+	PMU_PMEVCNTR_EL0(10),
+	PMU_PMEVCNTR_EL0(11),
+	PMU_PMEVCNTR_EL0(12),
+	PMU_PMEVCNTR_EL0(13),
+	PMU_PMEVCNTR_EL0(14),
+	PMU_PMEVCNTR_EL0(15),
+	PMU_PMEVCNTR_EL0(16),
+	PMU_PMEVCNTR_EL0(17),
+	PMU_PMEVCNTR_EL0(18),
+	PMU_PMEVCNTR_EL0(19),
+	PMU_PMEVCNTR_EL0(20),
+	PMU_PMEVCNTR_EL0(21),
+	PMU_PMEVCNTR_EL0(22),
+	PMU_PMEVCNTR_EL0(23),
+	PMU_PMEVCNTR_EL0(24),
+	PMU_PMEVCNTR_EL0(25),
+	PMU_PMEVCNTR_EL0(26),
+	PMU_PMEVCNTR_EL0(27),
+	PMU_PMEVCNTR_EL0(28),
+	PMU_PMEVCNTR_EL0(29),
+	PMU_PMEVCNTR_EL0(30),
 	/* PMEVTYPERn_EL0 */
 	PMU_PMEVTYPER_EL0(0),
 	PMU_PMEVTYPER_EL0(1),
@@ -1030,6 +1118,13 @@ static const struct sys_reg_desc cp14_64_regs[] = {
 	{ Op1( 0), CRm( 2), .access = trap_raz_wi },
 };
 
+/* Macro to expand the PMEVCNTRn register */
+#define PMU_PMEVCNTR(n)							\
+	/* PMEVCNTRn */							\
+	{ Op1(0), CRn(0b1110),						\
+	  CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evcntr }
+
 /* Macro to expand the PMEVTYPERn register */
 #define PMU_PMEVTYPER(n)						\
 	/* PMEVTYPERn */						\
@@ -1072,9 +1167,9 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
@@ -1089,6 +1184,38 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
 
+	/* PMEVCNTRn */
+	PMU_PMEVCNTR(0),
+	PMU_PMEVCNTR(1),
+	PMU_PMEVCNTR(2),
+	PMU_PMEVCNTR(3),
+	PMU_PMEVCNTR(4),
+	PMU_PMEVCNTR(5),
+	PMU_PMEVCNTR(6),
+	PMU_PMEVCNTR(7),
+	PMU_PMEVCNTR(8),
+	PMU_PMEVCNTR(9),
+	PMU_PMEVCNTR(10),
+	PMU_PMEVCNTR(11),
+	PMU_PMEVCNTR(12),
+	PMU_PMEVCNTR(13),
+	PMU_PMEVCNTR(14),
+	PMU_PMEVCNTR(15),
+	PMU_PMEVCNTR(16),
+	PMU_PMEVCNTR(17),
+	PMU_PMEVCNTR(18),
+	PMU_PMEVCNTR(19),
+	PMU_PMEVCNTR(20),
+	PMU_PMEVCNTR(21),
+	PMU_PMEVCNTR(22),
+	PMU_PMEVCNTR(23),
+	PMU_PMEVCNTR(24),
+	PMU_PMEVCNTR(25),
+	PMU_PMEVCNTR(26),
+	PMU_PMEVCNTR(27),
+	PMU_PMEVCNTR(28),
+	PMU_PMEVCNTR(29),
+	PMU_PMEVCNTR(30),
 	/* PMEVTYPERn */
 	PMU_PMEVTYPER(0),
 	PMU_PMEVTYPER(1),
@@ -1127,6 +1254,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 static const struct sys_reg_desc cp15_64_regs[] = {
 	{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
+	{ Op1( 0), CRn( 0), CRm( 9), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi },
 	{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
 };
-- 
2.0.4

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

* [PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
is mapped to PMEVCNTRn.

The access handler translates all aarch32 register offsets to aarch64
ones and uses vcpu_sys_reg() to access their values to avoid taking care
of big endian.

When reading these registers, return the sum of register value and the
value perf event counts.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 136 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 132 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index c52ff15..dc6bb26 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -566,6 +566,55 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
+			      struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 idx, reg, val;
+
+	if (!p->is_aarch32) {
+		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
+			/* PMXEVCNTR_EL0 */
+			reg = 0;
+		else
+			/* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
+			reg = r->reg;
+	} else {
+		if (r->CRn == 9 && r->CRm == 13) {
+			reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
+		} else {
+			reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
+			reg += PMEVCNTR0_EL0;
+		}
+	}
+
+	switch (reg) {
+	case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+		idx = reg - PMEVCNTR0_EL0;
+		break;
+	case PMCCNTR_EL0:
+		idx = ARMV8_CYCLE_IDX;
+		break;
+	default:
+		/* PMXEVCNTR_EL0 */
+		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
+		if (!pmu_counter_idx_valid(vcpu, idx))
+			return true;
+
+		reg = (idx == ARMV8_CYCLE_IDX) ? PMCCNTR_EL0
+						 : PMEVCNTR0_EL0 + idx;
+		break;
+	}
+
+	val = kvm_pmu_get_counter_value(vcpu, idx);
+	if (p->is_write)
+		vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
+	else
+		p->regval = val;
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -581,6 +630,13 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	{ Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111),	\
 	  trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
+/* Macro to expand the PMEVCNTRn_EL0 register */
+#define PMU_PMEVCNTR_EL0(n)						\
+	/* PMEVCNTRn_EL0 */						\
+	{ Op0(0b11), Op1(0b011), CRn(0b1110),				\
+	  CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evcntr, reset_unknown, (PMEVCNTR0_EL0 + n), }
+
 /* Macro to expand the PMEVTYPERn_EL0 register */
 #define PMU_PMEVTYPER_EL0(n)						\
 	/* PMEVTYPERn_EL0 */						\
@@ -781,13 +837,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmceid },
 	/* PMCCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmu_evcntr, reset_unknown, PMCCNTR_EL0 },
 	/* PMXEVTYPER_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
 	  access_pmu_evtyper },
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmu_evcntr },
 	/* PMUSERENR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
 	  trap_raz_wi },
@@ -802,6 +858,38 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
 	  NULL, reset_unknown, TPIDRRO_EL0 },
 
+	/* PMEVCNTRn_EL0 */
+	PMU_PMEVCNTR_EL0(0),
+	PMU_PMEVCNTR_EL0(1),
+	PMU_PMEVCNTR_EL0(2),
+	PMU_PMEVCNTR_EL0(3),
+	PMU_PMEVCNTR_EL0(4),
+	PMU_PMEVCNTR_EL0(5),
+	PMU_PMEVCNTR_EL0(6),
+	PMU_PMEVCNTR_EL0(7),
+	PMU_PMEVCNTR_EL0(8),
+	PMU_PMEVCNTR_EL0(9),
+	PMU_PMEVCNTR_EL0(10),
+	PMU_PMEVCNTR_EL0(11),
+	PMU_PMEVCNTR_EL0(12),
+	PMU_PMEVCNTR_EL0(13),
+	PMU_PMEVCNTR_EL0(14),
+	PMU_PMEVCNTR_EL0(15),
+	PMU_PMEVCNTR_EL0(16),
+	PMU_PMEVCNTR_EL0(17),
+	PMU_PMEVCNTR_EL0(18),
+	PMU_PMEVCNTR_EL0(19),
+	PMU_PMEVCNTR_EL0(20),
+	PMU_PMEVCNTR_EL0(21),
+	PMU_PMEVCNTR_EL0(22),
+	PMU_PMEVCNTR_EL0(23),
+	PMU_PMEVCNTR_EL0(24),
+	PMU_PMEVCNTR_EL0(25),
+	PMU_PMEVCNTR_EL0(26),
+	PMU_PMEVCNTR_EL0(27),
+	PMU_PMEVCNTR_EL0(28),
+	PMU_PMEVCNTR_EL0(29),
+	PMU_PMEVCNTR_EL0(30),
 	/* PMEVTYPERn_EL0 */
 	PMU_PMEVTYPER_EL0(0),
 	PMU_PMEVTYPER_EL0(1),
@@ -1030,6 +1118,13 @@ static const struct sys_reg_desc cp14_64_regs[] = {
 	{ Op1( 0), CRm( 2), .access = trap_raz_wi },
 };
 
+/* Macro to expand the PMEVCNTRn register */
+#define PMU_PMEVCNTR(n)							\
+	/* PMEVCNTRn */							\
+	{ Op1(0), CRn(0b1110),						\
+	  CRm((0b1000 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)),		\
+	  access_pmu_evcntr }
+
 /* Macro to expand the PMEVTYPERn register */
 #define PMU_PMEVTYPER(n)						\
 	/* PMEVTYPERn */						\
@@ -1072,9 +1167,9 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
-	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
@@ -1089,6 +1184,38 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
 
+	/* PMEVCNTRn */
+	PMU_PMEVCNTR(0),
+	PMU_PMEVCNTR(1),
+	PMU_PMEVCNTR(2),
+	PMU_PMEVCNTR(3),
+	PMU_PMEVCNTR(4),
+	PMU_PMEVCNTR(5),
+	PMU_PMEVCNTR(6),
+	PMU_PMEVCNTR(7),
+	PMU_PMEVCNTR(8),
+	PMU_PMEVCNTR(9),
+	PMU_PMEVCNTR(10),
+	PMU_PMEVCNTR(11),
+	PMU_PMEVCNTR(12),
+	PMU_PMEVCNTR(13),
+	PMU_PMEVCNTR(14),
+	PMU_PMEVCNTR(15),
+	PMU_PMEVCNTR(16),
+	PMU_PMEVCNTR(17),
+	PMU_PMEVCNTR(18),
+	PMU_PMEVCNTR(19),
+	PMU_PMEVCNTR(20),
+	PMU_PMEVCNTR(21),
+	PMU_PMEVCNTR(22),
+	PMU_PMEVCNTR(23),
+	PMU_PMEVCNTR(24),
+	PMU_PMEVCNTR(25),
+	PMU_PMEVCNTR(26),
+	PMU_PMEVCNTR(27),
+	PMU_PMEVCNTR(28),
+	PMU_PMEVCNTR(29),
+	PMU_PMEVCNTR(30),
 	/* PMEVTYPERn */
 	PMU_PMEVTYPER(0),
 	PMU_PMEVTYPER(1),
@@ -1127,6 +1254,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 static const struct sys_reg_desc cp15_64_regs[] = {
 	{ Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
+	{ Op1( 0), CRn( 0), CRm( 9), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi },
 	{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
 };
-- 
2.0.4

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

* [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMCNTENSET or PMCNTENCLR register.

When writing to PMCNTENSET, call perf_event_enable to enable the perf
event. When writing to PMCNTENCLR, call perf_event_disable to disable
the perf event.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 41 +++++++++++++++++++++++++++++++----
 include/kvm/arm_pmu.h     |  4 ++++
 virt/kvm/arm/pmu.c        | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index dc6bb26..f216da7 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
+{
+	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
+
+	val &= ARMV8_PMCR_N_MASK;
+	return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
+}
+
+static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 val, mask;
+
+	mask = kvm_pmu_valid_counter_mask(vcpu);
+	if (p->is_write) {
+		val = p->regval & mask;
+		if (r->Op2 & 0x1) {
+			/* accessing PMCNTENSET_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) |= val;
+			kvm_pmu_enable_counter(vcpu, val);
+		} else {
+			/* accessing PMCNTENCLR_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~val;
+			kvm_pmu_disable_counter(vcpu, val);
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmcr, reset_pmcr, PMCR_EL0, },
 	/* PMCNTENSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
 	/* PMCNTENCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
 	/* PMOVSCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
 	  trap_raz_wi },
@@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 	/* PMU */
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 14bedb0..43c4117 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,8 @@ struct kvm_pmu {
 };
 
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
 	return 0;
 }
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index b107fb8..94bff0e 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_enable_counter - enable selected PMU counter
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCNTENSET register
+ *
+ * Call perf_event_enable to start counting the perf event
+ */
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+
+	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) || !val)
+		return;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+
+		pmc = &pmu->pmc[i];
+		if (pmc->perf_event) {
+			perf_event_enable(pmc->perf_event);
+			if (pmc->perf_event->state != PERF_EVENT_STATE_ACTIVE)
+				kvm_debug("fail to enable perf event\n");
+		}
+	}
+}
+
+/**
+ * kvm_pmu_disable_counter - disable selected PMU counter
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCNTENCLR register
+ *
+ * Call perf_event_disable to stop counting the perf event
+ */
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+
+	if (!val)
+		return;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+
+		pmc = &pmu->pmc[i];
+		if (pmc->perf_event)
+			perf_event_disable(pmc->perf_event);
+	}
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
-- 
2.0.4

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

* [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMCNTENSET or PMCNTENCLR register.

When writing to PMCNTENSET, call perf_event_enable to enable the perf
event. When writing to PMCNTENCLR, call perf_event_disable to disable
the perf event.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 41 +++++++++++++++++++++++++++++++----
 include/kvm/arm_pmu.h     |  4 ++++
 virt/kvm/arm/pmu.c        | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index dc6bb26..f216da7 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
+{
+	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
+
+	val &= ARMV8_PMCR_N_MASK;
+	return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
+}
+
+static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 val, mask;
+
+	mask = kvm_pmu_valid_counter_mask(vcpu);
+	if (p->is_write) {
+		val = p->regval & mask;
+		if (r->Op2 & 0x1) {
+			/* accessing PMCNTENSET_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) |= val;
+			kvm_pmu_enable_counter(vcpu, val);
+		} else {
+			/* accessing PMCNTENCLR_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~val;
+			kvm_pmu_disable_counter(vcpu, val);
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmcr, reset_pmcr, PMCR_EL0, },
 	/* PMCNTENSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
 	/* PMCNTENCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
 	/* PMOVSCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
 	  trap_raz_wi },
@@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 	/* PMU */
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 14bedb0..43c4117 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,8 @@ struct kvm_pmu {
 };
 
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
 	return 0;
 }
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index b107fb8..94bff0e 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_enable_counter - enable selected PMU counter
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCNTENSET register
+ *
+ * Call perf_event_enable to start counting the perf event
+ */
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+
+	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) || !val)
+		return;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+
+		pmc = &pmu->pmc[i];
+		if (pmc->perf_event) {
+			perf_event_enable(pmc->perf_event);
+			if (pmc->perf_event->state != PERF_EVENT_STATE_ACTIVE)
+				kvm_debug("fail to enable perf event\n");
+		}
+	}
+}
+
+/**
+ * kvm_pmu_disable_counter - disable selected PMU counter
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCNTENCLR register
+ *
+ * Call perf_event_disable to stop counting the perf event
+ */
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+
+	if (!val)
+		return;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+
+		pmc = &pmu->pmc[i];
+		if (pmc->perf_event)
+			perf_event_disable(pmc->perf_event);
+	}
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
-- 
2.0.4

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

* [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMCNTENSET or PMCNTENCLR register.

When writing to PMCNTENSET, call perf_event_enable to enable the perf
event. When writing to PMCNTENCLR, call perf_event_disable to disable
the perf event.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 41 +++++++++++++++++++++++++++++++----
 include/kvm/arm_pmu.h     |  4 ++++
 virt/kvm/arm/pmu.c        | 55 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index dc6bb26..f216da7 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
+{
+	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
+
+	val &= ARMV8_PMCR_N_MASK;
+	return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
+}
+
+static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 val, mask;
+
+	mask = kvm_pmu_valid_counter_mask(vcpu);
+	if (p->is_write) {
+		val = p->regval & mask;
+		if (r->Op2 & 0x1) {
+			/* accessing PMCNTENSET_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) |= val;
+			kvm_pmu_enable_counter(vcpu, val);
+		} else {
+			/* accessing PMCNTENCLR_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~val;
+			kvm_pmu_disable_counter(vcpu, val);
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmcr, reset_pmcr, PMCR_EL0, },
 	/* PMCNTENSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
 	/* PMCNTENCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
 	/* PMOVSCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
 	  trap_raz_wi },
@@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 	/* PMU */
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 14bedb0..43c4117 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,8 @@ struct kvm_pmu {
 };
 
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
 	return 0;
 }
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index b107fb8..94bff0e 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_enable_counter - enable selected PMU counter
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCNTENSET register
+ *
+ * Call perf_event_enable to start counting the perf event
+ */
+void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+
+	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) || !val)
+		return;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+
+		pmc = &pmu->pmc[i];
+		if (pmc->perf_event) {
+			perf_event_enable(pmc->perf_event);
+			if (pmc->perf_event->state != PERF_EVENT_STATE_ACTIVE)
+				kvm_debug("fail to enable perf event\n");
+		}
+	}
+}
+
+/**
+ * kvm_pmu_disable_counter - disable selected PMU counter
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCNTENCLR register
+ *
+ * Call perf_event_disable to stop counting the perf event
+ */
+void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+
+	if (!val)
+		return;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+
+		pmc = &pmu->pmc[i];
+		if (pmc->perf_event)
+			perf_event_disable(pmc->perf_event);
+	}
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
-- 
2.0.4

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

* [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMINTENSET or PMINTENCLR register.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f216da7..594e53f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+	if (p->is_write) {
+		if (r->Op2 & 0x1) {
+			/* accessing PMINTENSET_EL1 */
+			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
+		} else {
+			/* accessing PMINTENCLR_EL1 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	/* PMINTENSET_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmintenset, reset_unknown, PMINTENSET_EL1 },
 	/* PMINTENCLR_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmintenset, NULL, PMINTENSET_EL1 },
 
 	/* MAIR_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
@@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
 
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
-- 
2.0.4

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

* [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMINTENSET or PMINTENCLR register.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f216da7..594e53f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+	if (p->is_write) {
+		if (r->Op2 & 0x1) {
+			/* accessing PMINTENSET_EL1 */
+			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
+		} else {
+			/* accessing PMINTENCLR_EL1 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	/* PMINTENSET_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmintenset, reset_unknown, PMINTENSET_EL1 },
 	/* PMINTENCLR_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmintenset, NULL, PMINTENSET_EL1 },
 
 	/* MAIR_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
@@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
 
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
-- 
2.0.4

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

* [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMINTENSET or PMINTENCLR register.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f216da7..594e53f 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
+{
+	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+	if (p->is_write) {
+		if (r->Op2 & 0x1) {
+			/* accessing PMINTENSET_EL1 */
+			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
+		} else {
+			/* accessing PMINTENCLR_EL1 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 
 	/* PMINTENSET_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
-	  trap_raz_wi },
+	  access_pmintenset, reset_unknown, PMINTENSET_EL1 },
 	/* PMINTENCLR_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
-	  trap_raz_wi },
+	  access_pmintenset, NULL, PMINTENSET_EL1 },
 
 	/* MAIR_EL1 */
 	{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
@@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
 
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
-- 
2.0.4

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

* [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMOVSSET or PMOVSCLR register.

When writing non-zero value to PMOVSSET, pend PMU interrupt.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 28 +++++++++++++++++++++++++---
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 20 ++++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 594e53f..d1926c4 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+	if (p->is_write) {
+		if (r->CRm & 0x2) {
+			/* accessing PMOVSSET_EL0 */
+			kvm_pmu_overflow_set(vcpu, p->regval & mask);
+		} else {
+			/* accessing PMOVSCLR_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
 	/* PMOVSCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
-	  trap_raz_wi },
+	  access_pmovsset, NULL, PMOVSSET_EL0 },
 	/* PMSWINC_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
 	  trap_raz_wi },
@@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMOVSSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
-	  trap_raz_wi },
+	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
 
 	/* TPIDR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
@@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
@@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
 
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 43c4117..93aea6a 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -38,6 +38,7 @@ struct kvm_pmu {
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 }
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 94bff0e..861471d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,26 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_overflow_set - set PMU overflow interrupt
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMOVSSET register
+ */
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
+{
+	u64 reg;
+
+	if (val == 0)
+		return;
+
+	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= val;
+	reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0)
+	      & vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
+	      & vcpu_sys_reg(vcpu, PMINTENSET_EL1);
+	if (reg != 0)
+		kvm_vcpu_kick(vcpu);
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
-- 
2.0.4



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

* [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMOVSSET or PMOVSCLR register.

When writing non-zero value to PMOVSSET, pend PMU interrupt.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 28 +++++++++++++++++++++++++---
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 20 ++++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 594e53f..d1926c4 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+	if (p->is_write) {
+		if (r->CRm & 0x2) {
+			/* accessing PMOVSSET_EL0 */
+			kvm_pmu_overflow_set(vcpu, p->regval & mask);
+		} else {
+			/* accessing PMOVSCLR_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
 	/* PMOVSCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
-	  trap_raz_wi },
+	  access_pmovsset, NULL, PMOVSSET_EL0 },
 	/* PMSWINC_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
 	  trap_raz_wi },
@@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMOVSSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
-	  trap_raz_wi },
+	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
 
 	/* TPIDR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
@@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
@@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
 
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 43c4117..93aea6a 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -38,6 +38,7 @@ struct kvm_pmu {
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 }
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 94bff0e..861471d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,26 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_overflow_set - set PMU overflow interrupt
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMOVSSET register
+ */
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
+{
+	u64 reg;
+
+	if (val == 0)
+		return;
+
+	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= val;
+	reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0)
+	      & vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
+	      & vcpu_sys_reg(vcpu, PMINTENSET_EL1);
+	if (reg != 0)
+		kvm_vcpu_kick(vcpu);
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
-- 
2.0.4



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

* [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
reset_unknown for its reset handler. Add a handler to emulate writing
PMOVSSET or PMOVSCLR register.

When writing non-zero value to PMOVSSET, pend PMU interrupt.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 28 +++++++++++++++++++++++++---
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 20 ++++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 594e53f..d1926c4 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			    const struct sys_reg_desc *r)
+{
+	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+
+	if (p->is_write) {
+		if (r->CRm & 0x2) {
+			/* accessing PMOVSSET_EL0 */
+			kvm_pmu_overflow_set(vcpu, p->regval & mask);
+		} else {
+			/* accessing PMOVSCLR_EL0 */
+			vcpu_sys_reg(vcpu, r->reg) &= mask;
+			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
+		}
+	} else {
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
 	/* PMOVSCLR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
-	  trap_raz_wi },
+	  access_pmovsset, NULL, PMOVSSET_EL0 },
 	/* PMSWINC_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
 	  trap_raz_wi },
@@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  trap_raz_wi },
 	/* PMOVSSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
-	  trap_raz_wi },
+	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
 
 	/* TPIDR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
@@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
-	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
@@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
 
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
 	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 43c4117..93aea6a 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -38,6 +38,7 @@ struct kvm_pmu {
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 }
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 94bff0e..861471d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,26 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_overflow_set - set PMU overflow interrupt
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMOVSSET register
+ */
+void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
+{
+	u64 reg;
+
+	if (val == 0)
+		return;
+
+	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= val;
+	reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0)
+	      & vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
+	      & vcpu_sys_reg(vcpu, PMINTENSET_EL1);
+	if (reg != 0)
+		kvm_vcpu_kick(vcpu);
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
-- 
2.0.4

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

* [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Add access handler which emulates writing and reading PMSWINC
register and add support for creating software increment event.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 14 +++++++++++++-
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d1926c4..f09e500 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			   const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		kvm_pmu_software_increment(vcpu, p->regval);
+		return true;
+	} else {
+		return read_zero(vcpu, p);
+	}
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmovsset, NULL, PMOVSSET_EL0 },
 	/* PMSWINC_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
-	  trap_raz_wi },
+	  access_pmswinc, reset_unknown, PMSWINC_EL0 },
 	/* PMSELR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
 	  access_pmselr, reset_unknown, PMSELR_EL0 },
@@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 93aea6a..f5888eb 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 861471d..01af727 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_software_increment - do software increment
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMSWINC register
+ */
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	u64 type, enable, reg;
+
+	if (val == 0)
+		return;
+
+	for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
+		       & ARMV8_EVTYPE_EVENT;
+		enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+		if ((type == 0) && ((enable >> i) & 0x1)) {
+			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
+			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
+			if ((reg & 0xFFFFFFFF) == 0)
+				kvm_pmu_overflow_set(vcpu, BIT(i));
+		}
+	}
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
@@ -171,6 +199,10 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	kvm_pmu_stop_counter(vcpu, pmc);
 	eventsel = data & ARMV8_EVTYPE_EVENT;
 
+	/* For software increment event it does't need to create perf event */
+	if (eventsel == 0)
+		return;
+
 	memset(&attr, 0, sizeof(struct perf_event_attr));
 	attr.type = PERF_TYPE_RAW;
 	attr.size = sizeof(attr);
-- 
2.0.4

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

* [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Add access handler which emulates writing and reading PMSWINC
register and add support for creating software increment event.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 14 +++++++++++++-
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d1926c4..f09e500 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			   const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		kvm_pmu_software_increment(vcpu, p->regval);
+		return true;
+	} else {
+		return read_zero(vcpu, p);
+	}
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmovsset, NULL, PMOVSSET_EL0 },
 	/* PMSWINC_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
-	  trap_raz_wi },
+	  access_pmswinc, reset_unknown, PMSWINC_EL0 },
 	/* PMSELR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
 	  access_pmselr, reset_unknown, PMSELR_EL0 },
@@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 93aea6a..f5888eb 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 861471d..01af727 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_software_increment - do software increment
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMSWINC register
+ */
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	u64 type, enable, reg;
+
+	if (val == 0)
+		return;
+
+	for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
+		       & ARMV8_EVTYPE_EVENT;
+		enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+		if ((type == 0) && ((enable >> i) & 0x1)) {
+			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
+			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
+			if ((reg & 0xFFFFFFFF) == 0)
+				kvm_pmu_overflow_set(vcpu, BIT(i));
+		}
+	}
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
@@ -171,6 +199,10 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	kvm_pmu_stop_counter(vcpu, pmc);
 	eventsel = data & ARMV8_EVTYPE_EVENT;
 
+	/* For software increment event it does't need to create perf event */
+	if (eventsel == 0)
+		return;
+
 	memset(&attr, 0, sizeof(struct perf_event_attr));
 	attr.type = PERF_TYPE_RAW;
 	attr.size = sizeof(attr);
-- 
2.0.4

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

* [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Add access handler which emulates writing and reading PMSWINC
register and add support for creating software increment event.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 14 +++++++++++++-
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index d1926c4..f09e500 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			   const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		kvm_pmu_software_increment(vcpu, p->regval);
+		return true;
+	} else {
+		return read_zero(vcpu, p);
+	}
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	  access_pmovsset, NULL, PMOVSSET_EL0 },
 	/* PMSWINC_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
-	  trap_raz_wi },
+	  access_pmswinc, reset_unknown, PMSWINC_EL0 },
 	/* PMSELR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
 	  access_pmselr, reset_unknown, PMSELR_EL0 },
@@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
+	{ Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
 	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 93aea6a..f5888eb 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
 #else
@@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 861471d..01af727 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_software_increment - do software increment
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMSWINC register
+ */
+void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
+{
+	int i;
+	u64 type, enable, reg;
+
+	if (val == 0)
+		return;
+
+	for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+		if (!((val >> i) & 0x1))
+			continue;
+		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
+		       & ARMV8_EVTYPE_EVENT;
+		enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
+		if ((type == 0) && ((enable >> i) & 0x1)) {
+			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
+			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
+			if ((reg & 0xFFFFFFFF) == 0)
+				kvm_pmu_overflow_set(vcpu, BIT(i));
+		}
+	}
+}
+
+/**
  * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
  * @vcpu: The vcpu pointer
  * @data: The data guest writes to PMXEVTYPER_EL0
@@ -171,6 +199,10 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	kvm_pmu_stop_counter(vcpu, pmc);
 	eventsel = data & ARMV8_EVTYPE_EVENT;
 
+	/* For software increment event it does't need to create perf event */
+	if (eventsel == 0)
+		return;
+
 	memset(&attr, 0, sizeof(struct perf_event_attr));
 	attr.type = PERF_TYPE_RAW;
 	attr.size = sizeof(attr);
-- 
2.0.4

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

* [PATCH v7 14/19] KVM: ARM64: Add helper to handle PMCR register bits
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

According to ARMv8 spec, when writing 1 to PMCR.E, all counters are
enabled by PMCNTENSET, while writing 0 to PMCR.E, all counters are
disabled. When writing 1 to PMCR.P, reset all event counters, not
including PMCCNTR, to zero. When writing 1 to PMCR.C, reset PMCCNTR to
zero.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c |  1 +
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f09e500..b2ccc25 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -463,6 +463,7 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		val &= ~ARMV8_PMCR_MASK;
 		val |= p->regval & ARMV8_PMCR_MASK;
 		vcpu_sys_reg(vcpu, r->reg) = val;
+		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
 		/* PMCR.P & PMCR.C are RAZ */
 		val = vcpu_sys_reg(vcpu, r->reg)
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index f5888eb..25b5f98 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -42,6 +42,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 #else
 struct kvm_pmu {
 };
@@ -56,6 +57,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 01af727..e664721 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,46 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_handle_pmcr - handle PMCR register
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCR register
+ */
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+	int i;
+
+	if (val & ARMV8_PMCR_E) {
+		kvm_pmu_enable_counter(vcpu,
+				       vcpu_sys_reg(vcpu, PMCNTENSET_EL0));
+	} else {
+		kvm_pmu_disable_counter(vcpu, 0xffffffffUL);
+	}
+
+	if (val & ARMV8_PMCR_C) {
+		pmc = &pmu->pmc[ARMV8_CYCLE_IDX];
+		if (pmc->perf_event)
+			local64_set(&pmc->perf_event->count, 0);
+		vcpu_sys_reg(vcpu, PMCCNTR_EL0) = 0;
+	}
+
+	if (val & ARMV8_PMCR_P) {
+		for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+			pmc = &pmu->pmc[i];
+			if (pmc->perf_event)
+				local64_set(&pmc->perf_event->count, 0);
+			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = 0;
+		}
+	}
+
+	if (val & ARMV8_PMCR_LC) {
+		pmc = &pmu->pmc[ARMV8_CYCLE_IDX];
+		pmc->bitmask = 0xffffffffffffffffUL;
+	}
+}
+
+/**
  * kvm_pmu_overflow_set - set PMU overflow interrupt
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMOVSSET register
-- 
2.0.4

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

* [PATCH v7 14/19] KVM: ARM64: Add helper to handle PMCR register bits
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

According to ARMv8 spec, when writing 1 to PMCR.E, all counters are
enabled by PMCNTENSET, while writing 0 to PMCR.E, all counters are
disabled. When writing 1 to PMCR.P, reset all event counters, not
including PMCCNTR, to zero. When writing 1 to PMCR.C, reset PMCCNTR to
zero.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c |  1 +
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f09e500..b2ccc25 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -463,6 +463,7 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		val &= ~ARMV8_PMCR_MASK;
 		val |= p->regval & ARMV8_PMCR_MASK;
 		vcpu_sys_reg(vcpu, r->reg) = val;
+		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
 		/* PMCR.P & PMCR.C are RAZ */
 		val = vcpu_sys_reg(vcpu, r->reg)
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index f5888eb..25b5f98 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -42,6 +42,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 #else
 struct kvm_pmu {
 };
@@ -56,6 +57,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 01af727..e664721 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,46 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_handle_pmcr - handle PMCR register
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCR register
+ */
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+	int i;
+
+	if (val & ARMV8_PMCR_E) {
+		kvm_pmu_enable_counter(vcpu,
+				       vcpu_sys_reg(vcpu, PMCNTENSET_EL0));
+	} else {
+		kvm_pmu_disable_counter(vcpu, 0xffffffffUL);
+	}
+
+	if (val & ARMV8_PMCR_C) {
+		pmc = &pmu->pmc[ARMV8_CYCLE_IDX];
+		if (pmc->perf_event)
+			local64_set(&pmc->perf_event->count, 0);
+		vcpu_sys_reg(vcpu, PMCCNTR_EL0) = 0;
+	}
+
+	if (val & ARMV8_PMCR_P) {
+		for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+			pmc = &pmu->pmc[i];
+			if (pmc->perf_event)
+				local64_set(&pmc->perf_event->count, 0);
+			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = 0;
+		}
+	}
+
+	if (val & ARMV8_PMCR_LC) {
+		pmc = &pmu->pmc[ARMV8_CYCLE_IDX];
+		pmc->bitmask = 0xffffffffffffffffUL;
+	}
+}
+
+/**
  * kvm_pmu_overflow_set - set PMU overflow interrupt
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMOVSSET register
-- 
2.0.4

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

* [PATCH v7 14/19] KVM: ARM64: Add helper to handle PMCR register bits
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

According to ARMv8 spec, when writing 1 to PMCR.E, all counters are
enabled by PMCNTENSET, while writing 0 to PMCR.E, all counters are
disabled. When writing 1 to PMCR.P, reset all event counters, not
including PMCCNTR, to zero. When writing 1 to PMCR.C, reset PMCCNTR to
zero.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c |  1 +
 include/kvm/arm_pmu.h     |  2 ++
 virt/kvm/arm/pmu.c        | 40 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 43 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f09e500..b2ccc25 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -463,6 +463,7 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		val &= ~ARMV8_PMCR_MASK;
 		val |= p->regval & ARMV8_PMCR_MASK;
 		vcpu_sys_reg(vcpu, r->reg) = val;
+		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
 		/* PMCR.P & PMCR.C are RAZ */
 		val = vcpu_sys_reg(vcpu, r->reg)
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index f5888eb..25b5f98 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -42,6 +42,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx);
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 #else
 struct kvm_pmu {
 };
@@ -56,6 +57,7 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
 void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 				    u64 select_idx) {}
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val) {}
 #endif
 
 #endif
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index 01af727..e664721 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -130,6 +130,46 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
 }
 
 /**
+ * kvm_pmu_handle_pmcr - handle PMCR register
+ * @vcpu: The vcpu pointer
+ * @val: the value guest writes to PMCR register
+ */
+void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	struct kvm_pmc *pmc;
+	int i;
+
+	if (val & ARMV8_PMCR_E) {
+		kvm_pmu_enable_counter(vcpu,
+				       vcpu_sys_reg(vcpu, PMCNTENSET_EL0));
+	} else {
+		kvm_pmu_disable_counter(vcpu, 0xffffffffUL);
+	}
+
+	if (val & ARMV8_PMCR_C) {
+		pmc = &pmu->pmc[ARMV8_CYCLE_IDX];
+		if (pmc->perf_event)
+			local64_set(&pmc->perf_event->count, 0);
+		vcpu_sys_reg(vcpu, PMCCNTR_EL0) = 0;
+	}
+
+	if (val & ARMV8_PMCR_P) {
+		for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
+			pmc = &pmu->pmc[i];
+			if (pmc->perf_event)
+				local64_set(&pmc->perf_event->count, 0);
+			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = 0;
+		}
+	}
+
+	if (val & ARMV8_PMCR_LC) {
+		pmc = &pmu->pmc[ARMV8_CYCLE_IDX];
+		pmc->bitmask = 0xffffffffffffffffUL;
+	}
+}
+
+/**
  * kvm_pmu_overflow_set - set PMU overflow interrupt
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMOVSSET register
-- 
2.0.4

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

* [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.

PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
accessed from EL0. Add some check helpers to handle the access from EL0.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 119 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b2ccc25..bad3dfd 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	vcpu_sys_reg(vcpu, r->reg) = val;
 }
 
+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
+}
+
 static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
 {
 	u64 val;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		/* Only update writeable bits of PMCR */
 		val = vcpu_sys_reg(vcpu, r->reg);
 		val &= ~ARMV8_PMCR_MASK;
@@ -465,6 +497,9 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		vcpu_sys_reg(vcpu, r->reg) = val;
 		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		/* PMCR.P & PMCR.C are RAZ */
 		val = vcpu_sys_reg(vcpu, r->reg)
 		      & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
@@ -477,9 +512,17 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			  const struct sys_reg_desc *r)
 {
+	bool unaccessible = pmu_access_event_counter_el0_disabled(vcpu);
+
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		vcpu_sys_reg(vcpu, r->reg) = p->regval;
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		/* return PMSELR.SEL field */
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
 	}
@@ -494,6 +537,8 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (p->is_write)
 		return write_to_read_only(vcpu, p);
+	else if (pmu_access_el0_disabled(vcpu))
+		return read_zero(vcpu, p);
 
 	if (!(p->Op2 & 1))
 		asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
@@ -521,6 +566,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			       const struct sys_reg_desc *r)
 {
 	u64 idx, reg;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (r->CRn == 9) {
 		/* PMXEVTYPER_EL0 */
@@ -558,9 +604,15 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	}
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
 		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
 	}
 
@@ -572,6 +624,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 			      const struct sys_reg_desc *r)
 {
 	u64 idx, reg, val;
+	bool unaccessible = false;
 
 	if (!p->is_aarch32) {
 		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
@@ -591,13 +644,22 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 
 	switch (reg) {
 	case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = reg - PMEVCNTR0_EL0;
 		break;
 	case PMCCNTR_EL0:
+		if (pmu_access_cycle_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = ARMV8_CYCLE_IDX;
 		break;
 	default:
 		/* PMXEVCNTR_EL0 */
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
 		if (!pmu_counter_idx_valid(vcpu, idx))
 			return true;
@@ -608,10 +670,17 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 	}
 
 	val = kvm_pmu_get_counter_value(vcpu, idx);
-	if (p->is_write)
+	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
-	else
+	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = val;
+	}
 
 	return true;
 }
@@ -628,9 +697,13 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			      const struct sys_reg_desc *r)
 {
 	u64 val, mask;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	mask = kvm_pmu_valid_counter_mask(vcpu);
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		val = p->regval & mask;
 		if (r->Op2 & 0x1) {
 			/* accessing PMCNTENSET_EL0 */
@@ -643,6 +716,9 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			kvm_pmu_disable_counter(vcpu, val);
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -653,8 +729,12 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			      const struct sys_reg_desc *r)
 {
 	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+	bool unaccessible = !vcpu_mode_priv(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		if (r->Op2 & 0x1) {
 			/* accessing PMINTENSET_EL1 */
 			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
@@ -664,6 +744,9 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -674,8 +757,12 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			    const struct sys_reg_desc *r)
 {
 	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		if (r->CRm & 0x2) {
 			/* accessing PMOVSSET_EL0 */
 			kvm_pmu_overflow_set(vcpu, p->regval & mask);
@@ -685,6 +772,9 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -695,6 +785,9 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			   const struct sys_reg_desc *r)
 {
 	if (p->is_write) {
+		if (pmu_write_swinc_el0_disabled(vcpu))
+			return ignore_write(vcpu, p);
+
 		kvm_pmu_software_increment(vcpu, p->regval);
 		return true;
 	} else {
@@ -702,6 +795,24 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	}
 }
 
+static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			     const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		if (!vcpu_mode_priv(vcpu))
+			return write_to_read_only(vcpu, p);
+
+		vcpu_sys_reg(vcpu, r->reg) = p->regval & 0xf;
+	} else {
+		if (pmu_access_el0_disabled(vcpu))
+			return read_zero(vcpu, p);
+
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & 0xf;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -931,9 +1042,12 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
 	  access_pmu_evcntr },
-	/* PMUSERENR_EL0 */
+	/* PMUSERENR_EL0
+	 * This register resets as unknown in 64bit mode while it resets as zero
+	 * in 32bit mode. Here we choose to reset it as zero for consistency.
+	 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmuserenr, reset_val, PMUSERENR_EL0, 0 },
 	/* PMOVSSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
 	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
@@ -1258,7 +1372,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), access_pmuserenr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
-- 
2.0.4



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

* [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.

PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
accessed from EL0. Add some check helpers to handle the access from EL0.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 119 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b2ccc25..bad3dfd 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	vcpu_sys_reg(vcpu, r->reg) = val;
 }
 
+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
+}
+
 static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
 {
 	u64 val;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		/* Only update writeable bits of PMCR */
 		val = vcpu_sys_reg(vcpu, r->reg);
 		val &= ~ARMV8_PMCR_MASK;
@@ -465,6 +497,9 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		vcpu_sys_reg(vcpu, r->reg) = val;
 		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		/* PMCR.P & PMCR.C are RAZ */
 		val = vcpu_sys_reg(vcpu, r->reg)
 		      & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
@@ -477,9 +512,17 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			  const struct sys_reg_desc *r)
 {
+	bool unaccessible = pmu_access_event_counter_el0_disabled(vcpu);
+
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		vcpu_sys_reg(vcpu, r->reg) = p->regval;
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		/* return PMSELR.SEL field */
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
 	}
@@ -494,6 +537,8 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (p->is_write)
 		return write_to_read_only(vcpu, p);
+	else if (pmu_access_el0_disabled(vcpu))
+		return read_zero(vcpu, p);
 
 	if (!(p->Op2 & 1))
 		asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
@@ -521,6 +566,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			       const struct sys_reg_desc *r)
 {
 	u64 idx, reg;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (r->CRn == 9) {
 		/* PMXEVTYPER_EL0 */
@@ -558,9 +604,15 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	}
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
 		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
 	}
 
@@ -572,6 +624,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 			      const struct sys_reg_desc *r)
 {
 	u64 idx, reg, val;
+	bool unaccessible = false;
 
 	if (!p->is_aarch32) {
 		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
@@ -591,13 +644,22 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 
 	switch (reg) {
 	case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = reg - PMEVCNTR0_EL0;
 		break;
 	case PMCCNTR_EL0:
+		if (pmu_access_cycle_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = ARMV8_CYCLE_IDX;
 		break;
 	default:
 		/* PMXEVCNTR_EL0 */
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
 		if (!pmu_counter_idx_valid(vcpu, idx))
 			return true;
@@ -608,10 +670,17 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 	}
 
 	val = kvm_pmu_get_counter_value(vcpu, idx);
-	if (p->is_write)
+	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
-	else
+	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = val;
+	}
 
 	return true;
 }
@@ -628,9 +697,13 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			      const struct sys_reg_desc *r)
 {
 	u64 val, mask;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	mask = kvm_pmu_valid_counter_mask(vcpu);
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		val = p->regval & mask;
 		if (r->Op2 & 0x1) {
 			/* accessing PMCNTENSET_EL0 */
@@ -643,6 +716,9 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			kvm_pmu_disable_counter(vcpu, val);
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -653,8 +729,12 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			      const struct sys_reg_desc *r)
 {
 	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+	bool unaccessible = !vcpu_mode_priv(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		if (r->Op2 & 0x1) {
 			/* accessing PMINTENSET_EL1 */
 			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
@@ -664,6 +744,9 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -674,8 +757,12 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			    const struct sys_reg_desc *r)
 {
 	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		if (r->CRm & 0x2) {
 			/* accessing PMOVSSET_EL0 */
 			kvm_pmu_overflow_set(vcpu, p->regval & mask);
@@ -685,6 +772,9 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -695,6 +785,9 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			   const struct sys_reg_desc *r)
 {
 	if (p->is_write) {
+		if (pmu_write_swinc_el0_disabled(vcpu))
+			return ignore_write(vcpu, p);
+
 		kvm_pmu_software_increment(vcpu, p->regval);
 		return true;
 	} else {
@@ -702,6 +795,24 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	}
 }
 
+static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			     const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		if (!vcpu_mode_priv(vcpu))
+			return write_to_read_only(vcpu, p);
+
+		vcpu_sys_reg(vcpu, r->reg) = p->regval & 0xf;
+	} else {
+		if (pmu_access_el0_disabled(vcpu))
+			return read_zero(vcpu, p);
+
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & 0xf;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -931,9 +1042,12 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
 	  access_pmu_evcntr },
-	/* PMUSERENR_EL0 */
+	/* PMUSERENR_EL0
+	 * This register resets as unknown in 64bit mode while it resets as zero
+	 * in 32bit mode. Here we choose to reset it as zero for consistency.
+	 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmuserenr, reset_val, PMUSERENR_EL0, 0 },
 	/* PMOVSSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
 	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
@@ -1258,7 +1372,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), access_pmuserenr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
-- 
2.0.4



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

* [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.

PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
accessed from EL0. Add some check helpers to handle the access from EL0.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 119 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index b2ccc25..bad3dfd 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 	vcpu_sys_reg(vcpu, r->reg) = val;
 }
 
+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
+}
+
+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
+{
+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
+
+	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
+}
+
 static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			const struct sys_reg_desc *r)
 {
 	u64 val;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		/* Only update writeable bits of PMCR */
 		val = vcpu_sys_reg(vcpu, r->reg);
 		val &= ~ARMV8_PMCR_MASK;
@@ -465,6 +497,9 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 		vcpu_sys_reg(vcpu, r->reg) = val;
 		kvm_pmu_handle_pmcr(vcpu, val);
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		/* PMCR.P & PMCR.C are RAZ */
 		val = vcpu_sys_reg(vcpu, r->reg)
 		      & ~(ARMV8_PMCR_P | ARMV8_PMCR_C);
@@ -477,9 +512,17 @@ static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			  const struct sys_reg_desc *r)
 {
+	bool unaccessible = pmu_access_event_counter_el0_disabled(vcpu);
+
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		vcpu_sys_reg(vcpu, r->reg) = p->regval;
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		/* return PMSELR.SEL field */
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & ARMV8_COUNTER_MASK;
 	}
@@ -494,6 +537,8 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 
 	if (p->is_write)
 		return write_to_read_only(vcpu, p);
+	else if (pmu_access_el0_disabled(vcpu))
+		return read_zero(vcpu, p);
 
 	if (!(p->Op2 & 1))
 		asm volatile("mrs %0, pmceid0_el0\n" : "=r" (pmceid));
@@ -521,6 +566,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			       const struct sys_reg_desc *r)
 {
 	u64 idx, reg;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (r->CRn == 9) {
 		/* PMXEVTYPER_EL0 */
@@ -558,9 +604,15 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	}
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
 		vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK;
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK;
 	}
 
@@ -572,6 +624,7 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 			      const struct sys_reg_desc *r)
 {
 	u64 idx, reg, val;
+	bool unaccessible = false;
 
 	if (!p->is_aarch32) {
 		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
@@ -591,13 +644,22 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 
 	switch (reg) {
 	case PMEVCNTR0_EL0 ... PMEVCNTR30_EL0:
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = reg - PMEVCNTR0_EL0;
 		break;
 	case PMCCNTR_EL0:
+		if (pmu_access_cycle_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = ARMV8_CYCLE_IDX;
 		break;
 	default:
 		/* PMXEVCNTR_EL0 */
+		if (pmu_access_event_counter_el0_disabled(vcpu))
+			unaccessible = true;
+
 		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
 		if (!pmu_counter_idx_valid(vcpu, idx))
 			return true;
@@ -608,10 +670,17 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
 	}
 
 	val = kvm_pmu_get_counter_value(vcpu, idx);
-	if (p->is_write)
+	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		vcpu_sys_reg(vcpu, reg) += (s64)p->regval - val;
-	else
+	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = val;
+	}
 
 	return true;
 }
@@ -628,9 +697,13 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			      const struct sys_reg_desc *r)
 {
 	u64 val, mask;
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	mask = kvm_pmu_valid_counter_mask(vcpu);
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		val = p->regval & mask;
 		if (r->Op2 & 0x1) {
 			/* accessing PMCNTENSET_EL0 */
@@ -643,6 +716,9 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			kvm_pmu_disable_counter(vcpu, val);
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -653,8 +729,12 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			      const struct sys_reg_desc *r)
 {
 	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+	bool unaccessible = !vcpu_mode_priv(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		if (r->Op2 & 0x1) {
 			/* accessing PMINTENSET_EL1 */
 			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
@@ -664,6 +744,9 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -674,8 +757,12 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			    const struct sys_reg_desc *r)
 {
 	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
+	bool unaccessible = pmu_access_el0_disabled(vcpu);
 
 	if (p->is_write) {
+		if (unaccessible)
+			return ignore_write(vcpu, p);
+
 		if (r->CRm & 0x2) {
 			/* accessing PMOVSSET_EL0 */
 			kvm_pmu_overflow_set(vcpu, p->regval & mask);
@@ -685,6 +772,9 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;
 		}
 	} else {
+		if (unaccessible)
+			return read_zero(vcpu, p);
+
 		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
 	}
 
@@ -695,6 +785,9 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 			   const struct sys_reg_desc *r)
 {
 	if (p->is_write) {
+		if (pmu_write_swinc_el0_disabled(vcpu))
+			return ignore_write(vcpu, p);
+
 		kvm_pmu_software_increment(vcpu, p->regval);
 		return true;
 	} else {
@@ -702,6 +795,24 @@ static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	}
 }
 
+static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
+			     const struct sys_reg_desc *r)
+{
+	if (p->is_write) {
+		if (!vcpu_mode_priv(vcpu))
+			return write_to_read_only(vcpu, p);
+
+		vcpu_sys_reg(vcpu, r->reg) = p->regval & 0xf;
+	} else {
+		if (pmu_access_el0_disabled(vcpu))
+			return read_zero(vcpu, p);
+
+		p->regval = vcpu_sys_reg(vcpu, r->reg) & 0xf;
+	}
+
+	return true;
+}
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	/* DBGBVRn_EL1 */						\
@@ -931,9 +1042,12 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	/* PMXEVCNTR_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
 	  access_pmu_evcntr },
-	/* PMUSERENR_EL0 */
+	/* PMUSERENR_EL0
+	 * This register resets as unknown in 64bit mode while it resets as zero
+	 * in 32bit mode. Here we choose to reset it as zero for consistency.
+	 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
-	  trap_raz_wi },
+	  access_pmuserenr, reset_val, PMUSERENR_EL0, 0 },
 	/* PMOVSSET_EL0 */
 	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
 	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
@@ -1258,7 +1372,7 @@ static const struct sys_reg_desc cp15_regs[] = {
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 0), access_pmu_evcntr },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
 	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
-	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
+	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), access_pmuserenr },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
 	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
-- 
2.0.4

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

* [PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

When calling perf_event_create_kernel_counter to create perf_event,
assign a overflow handler. Then when the perf event overflows, set the
corresponding bit of guest PMOVSSET register. If this counter is enabled
and its interrupt is enabled as well, kick the vcpu to sync the
interrupt.

On VM entry, if there is counter overflowed, inject the interrupt with
the level set to 1. Otherwise, inject the interrupt with the level set
to 0.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm/kvm/arm.c    |  2 ++
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c    | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index e06fd29..cd696ef 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -28,6 +28,7 @@
 #include <linux/sched.h>
 #include <linux/kvm.h>
 #include <trace/events/kvm.h>
+#include <kvm/arm_pmu.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 * non-preemptible context.
 		 */
 		preempt_disable();
+		kvm_pmu_flush_hwstate(vcpu);
 		kvm_timer_flush_hwstate(vcpu);
 		kvm_vgic_flush_hwstate(vcpu);
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 25b5f98..732ccaf 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -47,6 +48,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
 	return 0;
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index e664721..eff5b19 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -21,6 +21,7 @@
 #include <linux/perf_event.h>
 #include <asm/kvm_emulate.h>
 #include <kvm/arm_pmu.h>
+#include <kvm/arm_vgic.h>
 
 /**
  * kvm_pmu_get_counter_value - get PMU counter value
@@ -75,6 +76,56 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_flush_hwstate - flush pmu state to cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Inject virtual PMU IRQ if IRQ is pending for this cpu.
+ */
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	u64 overflow;
+
+	if (pmu->irq_num == -1)
+		return;
+
+	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
+		return;
+
+	overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
+		   & vcpu_sys_reg(vcpu, PMINTENSET_EL1)
+		   & vcpu_sys_reg(vcpu, PMOVSSET_EL0);
+
+	kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
+			    overflow ? 1 : 0);
+}
+
+static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
+{
+	struct kvm_pmu *pmu;
+	struct kvm_vcpu_arch *vcpu_arch;
+
+	pmc -= pmc->idx;
+	pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
+	vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
+	return container_of(vcpu_arch, struct kvm_vcpu, arch);
+}
+
+/**
+ * When perf event overflows, call kvm_pmu_overflow_set to set overflow status.
+ */
+static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
+				  struct perf_sample_data *data,
+				  struct pt_regs *regs)
+{
+	struct kvm_pmc *pmc = perf_event->overflow_handler_context;
+	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
+	int idx = pmc->idx;
+
+	kvm_pmu_overflow_set(vcpu, BIT(idx));
+}
+
+/**
  * kvm_pmu_enable_counter - enable selected PMU counter
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMCNTENSET register
@@ -258,7 +309,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	/* The initial sample period (overflow count) of an event. */
 	attr.sample_period = (-counter) & pmc->bitmask;
 
-	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
+	event = perf_event_create_kernel_counter(&attr, -1, current,
+						 kvm_pmu_perf_overflow, pmc);
 	if (IS_ERR(event)) {
 		printk_once("kvm: pmu event creation failed %ld\n",
 			    PTR_ERR(event));
-- 
2.0.4

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

* [PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

When calling perf_event_create_kernel_counter to create perf_event,
assign a overflow handler. Then when the perf event overflows, set the
corresponding bit of guest PMOVSSET register. If this counter is enabled
and its interrupt is enabled as well, kick the vcpu to sync the
interrupt.

On VM entry, if there is counter overflowed, inject the interrupt with
the level set to 1. Otherwise, inject the interrupt with the level set
to 0.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm/kvm/arm.c    |  2 ++
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c    | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index e06fd29..cd696ef 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -28,6 +28,7 @@
 #include <linux/sched.h>
 #include <linux/kvm.h>
 #include <trace/events/kvm.h>
+#include <kvm/arm_pmu.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 * non-preemptible context.
 		 */
 		preempt_disable();
+		kvm_pmu_flush_hwstate(vcpu);
 		kvm_timer_flush_hwstate(vcpu);
 		kvm_vgic_flush_hwstate(vcpu);
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 25b5f98..732ccaf 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -47,6 +48,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
 	return 0;
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index e664721..eff5b19 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -21,6 +21,7 @@
 #include <linux/perf_event.h>
 #include <asm/kvm_emulate.h>
 #include <kvm/arm_pmu.h>
+#include <kvm/arm_vgic.h>
 
 /**
  * kvm_pmu_get_counter_value - get PMU counter value
@@ -75,6 +76,56 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_flush_hwstate - flush pmu state to cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Inject virtual PMU IRQ if IRQ is pending for this cpu.
+ */
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	u64 overflow;
+
+	if (pmu->irq_num == -1)
+		return;
+
+	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
+		return;
+
+	overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
+		   & vcpu_sys_reg(vcpu, PMINTENSET_EL1)
+		   & vcpu_sys_reg(vcpu, PMOVSSET_EL0);
+
+	kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
+			    overflow ? 1 : 0);
+}
+
+static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
+{
+	struct kvm_pmu *pmu;
+	struct kvm_vcpu_arch *vcpu_arch;
+
+	pmc -= pmc->idx;
+	pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
+	vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
+	return container_of(vcpu_arch, struct kvm_vcpu, arch);
+}
+
+/**
+ * When perf event overflows, call kvm_pmu_overflow_set to set overflow status.
+ */
+static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
+				  struct perf_sample_data *data,
+				  struct pt_regs *regs)
+{
+	struct kvm_pmc *pmc = perf_event->overflow_handler_context;
+	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
+	int idx = pmc->idx;
+
+	kvm_pmu_overflow_set(vcpu, BIT(idx));
+}
+
+/**
  * kvm_pmu_enable_counter - enable selected PMU counter
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMCNTENSET register
@@ -258,7 +309,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	/* The initial sample period (overflow count) of an event. */
 	attr.sample_period = (-counter) & pmc->bitmask;
 
-	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
+	event = perf_event_create_kernel_counter(&attr, -1, current,
+						 kvm_pmu_perf_overflow, pmc);
 	if (IS_ERR(event)) {
 		printk_once("kvm: pmu event creation failed %ld\n",
 			    PTR_ERR(event));
-- 
2.0.4

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

* [PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

When calling perf_event_create_kernel_counter to create perf_event,
assign a overflow handler. Then when the perf event overflows, set the
corresponding bit of guest PMOVSSET register. If this counter is enabled
and its interrupt is enabled as well, kick the vcpu to sync the
interrupt.

On VM entry, if there is counter overflowed, inject the interrupt with
the level set to 1. Otherwise, inject the interrupt with the level set
to 0.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm/kvm/arm.c    |  2 ++
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c    | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index e06fd29..cd696ef 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -28,6 +28,7 @@
 #include <linux/sched.h>
 #include <linux/kvm.h>
 #include <trace/events/kvm.h>
+#include <kvm/arm_pmu.h>
 
 #define CREATE_TRACE_POINTS
 #include "trace.h"
@@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 * non-preemptible context.
 		 */
 		preempt_disable();
+		kvm_pmu_flush_hwstate(vcpu);
 		kvm_timer_flush_hwstate(vcpu);
 		kvm_vgic_flush_hwstate(vcpu);
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 25b5f98..732ccaf 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
 void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -47,6 +48,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
 	return 0;
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index e664721..eff5b19 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -21,6 +21,7 @@
 #include <linux/perf_event.h>
 #include <asm/kvm_emulate.h>
 #include <kvm/arm_pmu.h>
+#include <kvm/arm_vgic.h>
 
 /**
  * kvm_pmu_get_counter_value - get PMU counter value
@@ -75,6 +76,56 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_flush_hwstate - flush pmu state to cpu
+ * @vcpu: The vcpu pointer
+ *
+ * Inject virtual PMU IRQ if IRQ is pending for this cpu.
+ */
+void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
+{
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+	u64 overflow;
+
+	if (pmu->irq_num == -1)
+		return;
+
+	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
+		return;
+
+	overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
+		   & vcpu_sys_reg(vcpu, PMINTENSET_EL1)
+		   & vcpu_sys_reg(vcpu, PMOVSSET_EL0);
+
+	kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
+			    overflow ? 1 : 0);
+}
+
+static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
+{
+	struct kvm_pmu *pmu;
+	struct kvm_vcpu_arch *vcpu_arch;
+
+	pmc -= pmc->idx;
+	pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
+	vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
+	return container_of(vcpu_arch, struct kvm_vcpu, arch);
+}
+
+/**
+ * When perf event overflows, call kvm_pmu_overflow_set to set overflow status.
+ */
+static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
+				  struct perf_sample_data *data,
+				  struct pt_regs *regs)
+{
+	struct kvm_pmc *pmc = perf_event->overflow_handler_context;
+	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
+	int idx = pmc->idx;
+
+	kvm_pmu_overflow_set(vcpu, BIT(idx));
+}
+
+/**
  * kvm_pmu_enable_counter - enable selected PMU counter
  * @vcpu: The vcpu pointer
  * @val: the value guest writes to PMCNTENSET register
@@ -258,7 +309,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 	/* The initial sample period (overflow count) of an event. */
 	attr.sample_period = (-counter) & pmc->bitmask;
 
-	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
+	event = perf_event_create_kernel_counter(&attr, -1, current,
+						 kvm_pmu_perf_overflow, pmc);
 	if (IS_ERR(event)) {
 		printk_once("kvm: pmu event creation failed %ld\n",
 			    PTR_ERR(event));
-- 
2.0.4

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

* [PATCH v7 17/19] KVM: ARM64: Reset PMU state when resetting vcpu
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

When resetting vcpu, it needs to reset the PMU state to initial status.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/reset.c |  3 +++
 include/kvm/arm_pmu.h  |  2 ++
 virt/kvm/arm/pmu.c     | 17 +++++++++++++++++
 3 files changed, 22 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f34745c..dfbce78 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -120,6 +120,9 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 	/* Reset system registers */
 	kvm_reset_sys_regs(vcpu);
 
+	/* Reset PMU */
+	kvm_pmu_vcpu_reset(vcpu);
+
 	/* Reset timer */
 	return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
 }
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 732ccaf..59cb53c 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -48,6 +49,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index eff5b19..c62e7f5 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -76,6 +76,23 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_vcpu_reset - reset pmu state for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		kvm_pmu_stop_counter(vcpu, &pmu->pmc[i]);
+		pmu->pmc[i].idx = i;
+		pmu->pmc[i].bitmask = 0xffffffffUL;
+	}
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4



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

* [PATCH v7 17/19] KVM: ARM64: Reset PMU state when resetting vcpu
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

When resetting vcpu, it needs to reset the PMU state to initial status.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/reset.c |  3 +++
 include/kvm/arm_pmu.h  |  2 ++
 virt/kvm/arm/pmu.c     | 17 +++++++++++++++++
 3 files changed, 22 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f34745c..dfbce78 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -120,6 +120,9 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 	/* Reset system registers */
 	kvm_reset_sys_regs(vcpu);
 
+	/* Reset PMU */
+	kvm_pmu_vcpu_reset(vcpu);
+
 	/* Reset timer */
 	return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
 }
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 732ccaf..59cb53c 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -48,6 +49,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index eff5b19..c62e7f5 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -76,6 +76,23 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_vcpu_reset - reset pmu state for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		kvm_pmu_stop_counter(vcpu, &pmu->pmc[i]);
+		pmu->pmc[i].idx = i;
+		pmu->pmc[i].bitmask = 0xffffffffUL;
+	}
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4



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

* [PATCH v7 17/19] KVM: ARM64: Reset PMU state when resetting vcpu
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

When resetting vcpu, it needs to reset the PMU state to initial status.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm64/kvm/reset.c |  3 +++
 include/kvm/arm_pmu.h  |  2 ++
 virt/kvm/arm/pmu.c     | 17 +++++++++++++++++
 3 files changed, 22 insertions(+)

diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
index f34745c..dfbce78 100644
--- a/arch/arm64/kvm/reset.c
+++ b/arch/arm64/kvm/reset.c
@@ -120,6 +120,9 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
 	/* Reset system registers */
 	kvm_reset_sys_regs(vcpu);
 
+	/* Reset PMU */
+	kvm_pmu_vcpu_reset(vcpu);
+
 	/* Reset timer */
 	return kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
 }
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 732ccaf..59cb53c 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -35,6 +35,7 @@ struct kvm_pmu {
 	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -48,6 +49,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
 struct kvm_pmu {
 };
 
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index eff5b19..c62e7f5 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -76,6 +76,23 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
 }
 
 /**
+ * kvm_pmu_vcpu_reset - reset pmu state for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		kvm_pmu_stop_counter(vcpu, &pmu->pmc[i]);
+		pmu->pmc[i].idx = i;
+		pmu->pmc[i].bitmask = 0xffffffffUL;
+	}
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4

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

* [PATCH v7 18/19] KVM: ARM64: Free perf event of PMU when destroying vcpu
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

When KVM frees VCPU, it needs to free the perf_event of PMU.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm/kvm/arm.c    |  1 +
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c    | 21 +++++++++++++++++++++
 3 files changed, 24 insertions(+)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index cd696ef..cea2176 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -259,6 +259,7 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 	kvm_mmu_free_memory_caches(vcpu);
 	kvm_timer_vcpu_terminate(vcpu);
 	kvm_vgic_vcpu_destroy(vcpu);
+	kvm_pmu_vcpu_destroy(vcpu);
 	kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 59cb53c..b1b63ac 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -50,6 +51,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index c62e7f5..d113ee4 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -93,6 +93,27 @@ void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
 }
 
 /**
+ * kvm_pmu_vcpu_destroy - free perf event of PMU for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		struct kvm_pmc *pmc = &pmu->pmc[i];
+
+		if (pmc->perf_event) {
+			perf_event_disable(pmc->perf_event);
+			perf_event_release_kernel(pmc->perf_event);
+			pmc->perf_event = NULL;
+		}
+	}
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4



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

* [PATCH v7 18/19] KVM: ARM64: Free perf event of PMU when destroying vcpu
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai, zhaoshenglong

From: Shannon Zhao <shannon.zhao@linaro.org>

When KVM frees VCPU, it needs to free the perf_event of PMU.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm/kvm/arm.c    |  1 +
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c    | 21 +++++++++++++++++++++
 3 files changed, 24 insertions(+)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index cd696ef..cea2176 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -259,6 +259,7 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 	kvm_mmu_free_memory_caches(vcpu);
 	kvm_timer_vcpu_terminate(vcpu);
 	kvm_vgic_vcpu_destroy(vcpu);
+	kvm_pmu_vcpu_destroy(vcpu);
 	kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 59cb53c..b1b63ac 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -50,6 +51,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index c62e7f5..d113ee4 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -93,6 +93,27 @@ void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
 }
 
 /**
+ * kvm_pmu_vcpu_destroy - free perf event of PMU for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		struct kvm_pmc *pmc = &pmu->pmc[i];
+
+		if (pmc->perf_event) {
+			perf_event_disable(pmc->perf_event);
+			perf_event_release_kernel(pmc->perf_event);
+			pmc->perf_event = NULL;
+		}
+	}
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4



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

* [PATCH v7 18/19] KVM: ARM64: Free perf event of PMU when destroying vcpu
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

When KVM frees VCPU, it needs to free the perf_event of PMU.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 arch/arm/kvm/arm.c    |  1 +
 include/kvm/arm_pmu.h |  2 ++
 virt/kvm/arm/pmu.c    | 21 +++++++++++++++++++++
 3 files changed, 24 insertions(+)

diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index cd696ef..cea2176 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -259,6 +259,7 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 	kvm_mmu_free_memory_caches(vcpu);
 	kvm_timer_vcpu_terminate(vcpu);
 	kvm_vgic_vcpu_destroy(vcpu);
+	kvm_pmu_vcpu_destroy(vcpu);
 	kmem_cache_free(kvm_vcpu_cache, vcpu);
 }
 
diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
index 59cb53c..b1b63ac 100644
--- a/include/kvm/arm_pmu.h
+++ b/include/kvm/arm_pmu.h
@@ -36,6 +36,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
@@ -50,6 +51,7 @@ struct kvm_pmu {
 };
 
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu) {}
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) {}
 void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
 {
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index c62e7f5..d113ee4 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -93,6 +93,27 @@ void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu)
 }
 
 /**
+ * kvm_pmu_vcpu_destroy - free perf event of PMU for cpu
+ * @vcpu: The vcpu pointer
+ *
+ */
+void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu)
+{
+	int i;
+	struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
+		struct kvm_pmc *pmc = &pmu->pmc[i];
+
+		if (pmc->perf_event) {
+			perf_event_disable(pmc->perf_event);
+			perf_event_release_kernel(pmc->perf_event);
+			pmc->perf_event = NULL;
+		}
+	}
+}
+
+/**
  * kvm_pmu_flush_hwstate - flush pmu state to cpu
  * @vcpu: The vcpu pointer
  *
-- 
2.0.4

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-15  8:49 ` Shannon Zhao
  (?)
@ 2015-12-15  8:49   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
the kvm_device_ops for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
 arch/arm64/include/uapi/asm/kvm.h             |   3 +
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
 virt/kvm/kvm_main.c                           |   4 +
 6 files changed, 141 insertions(+)
 create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt

diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
new file mode 100644
index 0000000..5121f1f
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
@@ -0,0 +1,16 @@
+ARM Virtual Performance Monitor Unit (vPMU)
+===========================================
+
+Device types supported:
+  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
+
+Instantiate one PMU instance for per VCPU through this API.
+
+Groups:
+  KVM_DEV_ARM_PMU_GRP_IRQ
+  Attributes:
+    A value describing the interrupt number of PMU overflow interrupt. This
+    interrupt should be a PPI.
+
+  Errors:
+    -EINVAL: Value set is out of the expected range (from 16 to 31)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 2d4ca4b..568afa2 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
+/* Device Control API: ARM PMU */
+#define KVM_DEV_ARM_PMU_GRP_IRQ		0
+
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
 #define KVM_ARM_IRQ_TYPE_MASK		0xff
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index c923350..608dea6 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_xics_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
+extern struct kvm_device_ops kvm_arm_pmu_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 03f3618..4ba6fdd 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1032,6 +1032,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
 	KVM_DEV_TYPE_ARM_VGIC_V3,
 #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
+	KVM_DEV_TYPE_ARM_PMU_V3,
+#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
 	KVM_DEV_TYPE_MAX,
 };
 
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index d113ee4..1965d0d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -19,6 +19,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/perf_event.h>
+#include <linux/uaccess.h>
 #include <asm/kvm_emulate.h>
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_vgic.h>
@@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 
 	pmc->perf_event = event;
 }
+
+static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.pmu.irq_num != -1;
+}
+
+static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
+{
+	int j;
+	struct kvm_vcpu *vcpu;
+
+	kvm_for_each_vcpu(j, vcpu, kvm) {
+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+		if (!is_set) {
+			if (!kvm_arm_pmu_initialized(vcpu))
+				return -EBUSY;
+
+			*irq = pmu->irq_num;
+			break;
+		}
+
+		if (kvm_arm_pmu_initialized(vcpu))
+			return -EBUSY;
+
+		kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
+		pmu->irq_num = *irq;
+	}
+
+	return 0;
+}
+
+static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
+{
+	int i;
+	struct kvm_vcpu *vcpu;
+	struct kvm *kvm = dev->kvm;
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+		memset(pmu, 0, sizeof(*pmu));
+		kvm_pmu_vcpu_reset(vcpu);
+		pmu->irq_num = -1;
+	}
+
+	return 0;
+}
+
+static void kvm_arm_pmu_destroy(struct kvm_device *dev)
+{
+	kfree(dev);
+}
+
+static int kvm_arm_pmu_set_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
+
+		if (reg < VGIC_NR_SGIS || reg >= VGIC_NR_PRIVATE_IRQS)
+			return -EINVAL;
+
+		return kvm_arm_pmu_irq_access(dev->kvm, &reg, true);
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int kvm_arm_pmu_get_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	int ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int reg = -1;
+
+		ret = kvm_arm_pmu_irq_access(dev->kvm, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int kvm_arm_pmu_has_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ:
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_pmu_ops = {
+	.name = "kvm-arm-pmu",
+	.create = kvm_arm_pmu_create,
+	.destroy = kvm_arm_pmu_destroy,
+	.set_attr = kvm_arm_pmu_set_attr,
+	.get_attr = kvm_arm_pmu_get_attr,
+	.has_attr = kvm_arm_pmu_has_attr,
+};
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 484079e..81a42cc 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2647,6 +2647,10 @@ static struct kvm_device_ops *kvm_device_ops_table[KVM_DEV_TYPE_MAX] = {
 #ifdef CONFIG_KVM_XICS
 	[KVM_DEV_TYPE_XICS]		= &kvm_xics_ops,
 #endif
+
+#ifdef CONFIG_KVM_ARM_PMU
+	[KVM_DEV_TYPE_ARM_PMU_V3]	= &kvm_arm_pmu_ops,
+#endif
 };
 
 int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type)
-- 
2.0.4

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: kvmarm, marc.zyngier, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

From: Shannon Zhao <shannon.zhao@linaro.org>

Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
the kvm_device_ops for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
 arch/arm64/include/uapi/asm/kvm.h             |   3 +
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
 virt/kvm/kvm_main.c                           |   4 +
 6 files changed, 141 insertions(+)
 create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt

diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
new file mode 100644
index 0000000..5121f1f
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
@@ -0,0 +1,16 @@
+ARM Virtual Performance Monitor Unit (vPMU)
+===========================================
+
+Device types supported:
+  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
+
+Instantiate one PMU instance for per VCPU through this API.
+
+Groups:
+  KVM_DEV_ARM_PMU_GRP_IRQ
+  Attributes:
+    A value describing the interrupt number of PMU overflow interrupt. This
+    interrupt should be a PPI.
+
+  Errors:
+    -EINVAL: Value set is out of the expected range (from 16 to 31)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 2d4ca4b..568afa2 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
+/* Device Control API: ARM PMU */
+#define KVM_DEV_ARM_PMU_GRP_IRQ		0
+
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
 #define KVM_ARM_IRQ_TYPE_MASK		0xff
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index c923350..608dea6 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_xics_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
+extern struct kvm_device_ops kvm_arm_pmu_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 03f3618..4ba6fdd 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1032,6 +1032,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
 	KVM_DEV_TYPE_ARM_VGIC_V3,
 #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
+	KVM_DEV_TYPE_ARM_PMU_V3,
+#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
 	KVM_DEV_TYPE_MAX,
 };
 
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index d113ee4..1965d0d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -19,6 +19,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/perf_event.h>
+#include <linux/uaccess.h>
 #include <asm/kvm_emulate.h>
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_vgic.h>
@@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 
 	pmc->perf_event = event;
 }
+
+static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.pmu.irq_num != -1;
+}
+
+static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
+{
+	int j;
+	struct kvm_vcpu *vcpu;
+
+	kvm_for_each_vcpu(j, vcpu, kvm) {
+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+		if (!is_set) {
+			if (!kvm_arm_pmu_initialized(vcpu))
+				return -EBUSY;
+
+			*irq = pmu->irq_num;
+			break;
+		}
+
+		if (kvm_arm_pmu_initialized(vcpu))
+			return -EBUSY;
+
+		kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
+		pmu->irq_num = *irq;
+	}
+
+	return 0;
+}
+
+static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
+{
+	int i;
+	struct kvm_vcpu *vcpu;
+	struct kvm *kvm = dev->kvm;
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+		memset(pmu, 0, sizeof(*pmu));
+		kvm_pmu_vcpu_reset(vcpu);
+		pmu->irq_num = -1;
+	}
+
+	return 0;
+}
+
+static void kvm_arm_pmu_destroy(struct kvm_device *dev)
+{
+	kfree(dev);
+}
+
+static int kvm_arm_pmu_set_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
+
+		if (reg < VGIC_NR_SGIS || reg >= VGIC_NR_PRIVATE_IRQS)
+			return -EINVAL;
+
+		return kvm_arm_pmu_irq_access(dev->kvm, &reg, true);
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int kvm_arm_pmu_get_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	int ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int reg = -1;
+
+		ret = kvm_arm_pmu_irq_access(dev->kvm, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int kvm_arm_pmu_has_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ:
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_pmu_ops = {
+	.name = "kvm-arm-pmu",
+	.create = kvm_arm_pmu_create,
+	.destroy = kvm_arm_pmu_destroy,
+	.set_attr = kvm_arm_pmu_set_attr,
+	.get_attr = kvm_arm_pmu_get_attr,
+	.has_attr = kvm_arm_pmu_has_attr,
+};
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 484079e..81a42cc 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2647,6 +2647,10 @@ static struct kvm_device_ops *kvm_device_ops_table[KVM_DEV_TYPE_MAX] = {
 #ifdef CONFIG_KVM_XICS
 	[KVM_DEV_TYPE_XICS]		= &kvm_xics_ops,
 #endif
+
+#ifdef CONFIG_KVM_ARM_PMU
+	[KVM_DEV_TYPE_ARM_PMU_V3]	= &kvm_arm_pmu_ops,
+#endif
 };
 
 int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type)
-- 
2.0.4

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15  8:49   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

From: Shannon Zhao <shannon.zhao@linaro.org>

Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
the kvm_device_ops for it.

Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
---
 Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
 arch/arm64/include/uapi/asm/kvm.h             |   3 +
 include/linux/kvm_host.h                      |   1 +
 include/uapi/linux/kvm.h                      |   2 +
 virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
 virt/kvm/kvm_main.c                           |   4 +
 6 files changed, 141 insertions(+)
 create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt

diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
new file mode 100644
index 0000000..5121f1f
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
@@ -0,0 +1,16 @@
+ARM Virtual Performance Monitor Unit (vPMU)
+===========================================
+
+Device types supported:
+  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
+
+Instantiate one PMU instance for per VCPU through this API.
+
+Groups:
+  KVM_DEV_ARM_PMU_GRP_IRQ
+  Attributes:
+    A value describing the interrupt number of PMU overflow interrupt. This
+    interrupt should be a PPI.
+
+  Errors:
+    -EINVAL: Value set is out of the expected range (from 16 to 31)
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 2d4ca4b..568afa2 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
 #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
 #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
 
+/* Device Control API: ARM PMU */
+#define KVM_DEV_ARM_PMU_GRP_IRQ		0
+
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT		24
 #define KVM_ARM_IRQ_TYPE_MASK		0xff
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index c923350..608dea6 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
 extern struct kvm_device_ops kvm_xics_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
 extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
+extern struct kvm_device_ops kvm_arm_pmu_ops;
 
 #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 03f3618..4ba6fdd 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1032,6 +1032,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
 	KVM_DEV_TYPE_ARM_VGIC_V3,
 #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
+	KVM_DEV_TYPE_ARM_PMU_V3,
+#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
 	KVM_DEV_TYPE_MAX,
 };
 
diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
index d113ee4..1965d0d 100644
--- a/virt/kvm/arm/pmu.c
+++ b/virt/kvm/arm/pmu.c
@@ -19,6 +19,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/perf_event.h>
+#include <linux/uaccess.h>
 #include <asm/kvm_emulate.h>
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_vgic.h>
@@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
 
 	pmc->perf_event = event;
 }
+
+static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.pmu.irq_num != -1;
+}
+
+static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
+{
+	int j;
+	struct kvm_vcpu *vcpu;
+
+	kvm_for_each_vcpu(j, vcpu, kvm) {
+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+		if (!is_set) {
+			if (!kvm_arm_pmu_initialized(vcpu))
+				return -EBUSY;
+
+			*irq = pmu->irq_num;
+			break;
+		}
+
+		if (kvm_arm_pmu_initialized(vcpu))
+			return -EBUSY;
+
+		kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
+		pmu->irq_num = *irq;
+	}
+
+	return 0;
+}
+
+static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
+{
+	int i;
+	struct kvm_vcpu *vcpu;
+	struct kvm *kvm = dev->kvm;
+
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
+
+		memset(pmu, 0, sizeof(*pmu));
+		kvm_pmu_vcpu_reset(vcpu);
+		pmu->irq_num = -1;
+	}
+
+	return 0;
+}
+
+static void kvm_arm_pmu_destroy(struct kvm_device *dev)
+{
+	kfree(dev);
+}
+
+static int kvm_arm_pmu_set_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int reg;
+
+		if (get_user(reg, uaddr))
+			return -EFAULT;
+
+		if (reg < VGIC_NR_SGIS || reg >= VGIC_NR_PRIVATE_IRQS)
+			return -EINVAL;
+
+		return kvm_arm_pmu_irq_access(dev->kvm, &reg, true);
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int kvm_arm_pmu_get_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	int ret;
+
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ: {
+		int __user *uaddr = (int __user *)(long)attr->addr;
+		int reg = -1;
+
+		ret = kvm_arm_pmu_irq_access(dev->kvm, &reg, false);
+		if (ret)
+			return ret;
+		return put_user(reg, uaddr);
+	}
+	}
+
+	return -ENXIO;
+}
+
+static int kvm_arm_pmu_has_attr(struct kvm_device *dev,
+				struct kvm_device_attr *attr)
+{
+	switch (attr->group) {
+	case KVM_DEV_ARM_PMU_GRP_IRQ:
+		return 0;
+	}
+
+	return -ENXIO;
+}
+
+struct kvm_device_ops kvm_arm_pmu_ops = {
+	.name = "kvm-arm-pmu",
+	.create = kvm_arm_pmu_create,
+	.destroy = kvm_arm_pmu_destroy,
+	.set_attr = kvm_arm_pmu_set_attr,
+	.get_attr = kvm_arm_pmu_get_attr,
+	.has_attr = kvm_arm_pmu_has_attr,
+};
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 484079e..81a42cc 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2647,6 +2647,10 @@ static struct kvm_device_ops *kvm_device_ops_table[KVM_DEV_TYPE_MAX] = {
 #ifdef CONFIG_KVM_XICS
 	[KVM_DEV_TYPE_XICS]		= &kvm_xics_ops,
 #endif
+
+#ifdef CONFIG_KVM_ARM_PMU
+	[KVM_DEV_TYPE_ARM_PMU_V3]	= &kvm_arm_pmu_ops,
+#endif
 };
 
 int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type)
-- 
2.0.4

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

* Re: [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 11:34     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 11:34 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> To use the ARMv8 PMU related register defines from the KVM code,
> we move the relevant definitions to asm/pmu.h header file.
> 
> Signed-off-by: Anup Patel <anup.patel@linaro.org>
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/include/asm/pmu.h   | 64 ++++++++++++++++++++++++++++++++++++++++++
>  arch/arm64/kernel/perf_event.c | 36 +-----------------------
>  2 files changed, 65 insertions(+), 35 deletions(-)
>  create mode 100644 arch/arm64/include/asm/pmu.h
> 
> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
> new file mode 100644
> index 0000000..4264ea0
> --- /dev/null
> +++ b/arch/arm64/include/asm/pmu.h
> @@ -0,0 +1,64 @@
> +/*
> + * Copyright (C) 2015 Linaro Ltd, Shannon Zhao

Erm, not quite. You're simply moving existing code from one file to
another. That doesn't change the copyright of said code, which reads:

 * PMU support
 *
 * Copyright (C) 2012 ARM Limited
 * Author: Will Deacon <will.deacon@arm.com>

Please keep this mention in place.

> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_PMU_H
> +#define __ASM_PMU_H
> +
> +#define ARMV8_MAX_COUNTERS      32
> +#define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
> +
> +/*
> + * Per-CPU PMCR: config reg
> + */
> +#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
> +#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
> +#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
> +#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
> +#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
> +#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
> +#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
> +#define	ARMV8_PMCR_N_MASK	0x1f
> +#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
> +
> +/*
> + * PMCNTEN: counters enable reg
> + */
> +#define	ARMV8_CNTEN_MASK	0xffffffff	/* Mask for writable bits */
> +
> +/*
> + * PMINTEN: counters interrupt enable reg
> + */
> +#define	ARMV8_INTEN_MASK	0xffffffff	/* Mask for writable bits */
> +
> +/*
> + * PMOVSR: counters overflow flag status reg
> + */
> +#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
> +#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
> +
> +/*
> + * PMXEVTYPER: Event selection reg
> + */
> +#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
> +#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
> +
> +/*
> + * Event filters for PMUv3
> + */
> +#define	ARMV8_EXCLUDE_EL1	(1 << 31)
> +#define	ARMV8_EXCLUDE_EL0	(1 << 30)
> +#define	ARMV8_INCLUDE_EL2	(1 << 27)
> +
> +#endif /* __ASM_PMU_H */
> diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
> index 5b1897e..7eca5dc 100644
> --- a/arch/arm64/kernel/perf_event.c
> +++ b/arch/arm64/kernel/perf_event.c
> @@ -24,6 +24,7 @@
>  #include <linux/of.h>
>  #include <linux/perf/arm_pmu.h>
>  #include <linux/platform_device.h>
> +#include <asm/pmu.h>
>  
>  /*
>   * ARMv8 PMUv3 Performance Events handling code.
> @@ -187,9 +188,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
>  #define	ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
>  	(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
>  
> -#define	ARMV8_MAX_COUNTERS	32
> -#define	ARMV8_COUNTER_MASK	(ARMV8_MAX_COUNTERS - 1)
> -
>  /*
>   * ARMv8 low level PMU access
>   */
> @@ -200,38 +198,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
>  #define	ARMV8_IDX_TO_COUNTER(x)	\
>  	(((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
>  
> -/*
> - * Per-CPU PMCR: config reg
> - */
> -#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
> -#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
> -#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
> -#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
> -#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
> -#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
> -#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
> -#define	ARMV8_PMCR_N_MASK	0x1f
> -#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
> -
> -/*
> - * PMOVSR: counters overflow flag status reg
> - */
> -#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
> -#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
> -
> -/*
> - * PMXEVTYPER: Event selection reg
> - */
> -#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
> -#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
> -
> -/*
> - * Event filters for PMUv3
> - */
> -#define	ARMV8_EXCLUDE_EL1	(1 << 31)
> -#define	ARMV8_EXCLUDE_EL0	(1 << 30)
> -#define	ARMV8_INCLUDE_EL2	(1 << 27)
> -
>  static inline u32 armv8pmu_pmcr_read(void)
>  {
>  	u32 val;
> 

Thanks,

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

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

* [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h
@ 2015-12-15 11:34     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 11:34 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> To use the ARMv8 PMU related register defines from the KVM code,
> we move the relevant definitions to asm/pmu.h header file.
> 
> Signed-off-by: Anup Patel <anup.patel@linaro.org>
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/include/asm/pmu.h   | 64 ++++++++++++++++++++++++++++++++++++++++++
>  arch/arm64/kernel/perf_event.c | 36 +-----------------------
>  2 files changed, 65 insertions(+), 35 deletions(-)
>  create mode 100644 arch/arm64/include/asm/pmu.h
> 
> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
> new file mode 100644
> index 0000000..4264ea0
> --- /dev/null
> +++ b/arch/arm64/include/asm/pmu.h
> @@ -0,0 +1,64 @@
> +/*
> + * Copyright (C) 2015 Linaro Ltd, Shannon Zhao

Erm, not quite. You're simply moving existing code from one file to
another. That doesn't change the copyright of said code, which reads:

 * PMU support
 *
 * Copyright (C) 2012 ARM Limited
 * Author: Will Deacon <will.deacon@arm.com>

Please keep this mention in place.

> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_PMU_H
> +#define __ASM_PMU_H
> +
> +#define ARMV8_MAX_COUNTERS      32
> +#define ARMV8_COUNTER_MASK      (ARMV8_MAX_COUNTERS - 1)
> +
> +/*
> + * Per-CPU PMCR: config reg
> + */
> +#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
> +#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
> +#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
> +#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
> +#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
> +#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
> +#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
> +#define	ARMV8_PMCR_N_MASK	0x1f
> +#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
> +
> +/*
> + * PMCNTEN: counters enable reg
> + */
> +#define	ARMV8_CNTEN_MASK	0xffffffff	/* Mask for writable bits */
> +
> +/*
> + * PMINTEN: counters interrupt enable reg
> + */
> +#define	ARMV8_INTEN_MASK	0xffffffff	/* Mask for writable bits */
> +
> +/*
> + * PMOVSR: counters overflow flag status reg
> + */
> +#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
> +#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
> +
> +/*
> + * PMXEVTYPER: Event selection reg
> + */
> +#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
> +#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
> +
> +/*
> + * Event filters for PMUv3
> + */
> +#define	ARMV8_EXCLUDE_EL1	(1 << 31)
> +#define	ARMV8_EXCLUDE_EL0	(1 << 30)
> +#define	ARMV8_INCLUDE_EL2	(1 << 27)
> +
> +#endif /* __ASM_PMU_H */
> diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
> index 5b1897e..7eca5dc 100644
> --- a/arch/arm64/kernel/perf_event.c
> +++ b/arch/arm64/kernel/perf_event.c
> @@ -24,6 +24,7 @@
>  #include <linux/of.h>
>  #include <linux/perf/arm_pmu.h>
>  #include <linux/platform_device.h>
> +#include <asm/pmu.h>
>  
>  /*
>   * ARMv8 PMUv3 Performance Events handling code.
> @@ -187,9 +188,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
>  #define	ARMV8_IDX_COUNTER_LAST(cpu_pmu) \
>  	(ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
>  
> -#define	ARMV8_MAX_COUNTERS	32
> -#define	ARMV8_COUNTER_MASK	(ARMV8_MAX_COUNTERS - 1)
> -
>  /*
>   * ARMv8 low level PMU access
>   */
> @@ -200,38 +198,6 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
>  #define	ARMV8_IDX_TO_COUNTER(x)	\
>  	(((x) - ARMV8_IDX_COUNTER0) & ARMV8_COUNTER_MASK)
>  
> -/*
> - * Per-CPU PMCR: config reg
> - */
> -#define ARMV8_PMCR_E		(1 << 0) /* Enable all counters */
> -#define ARMV8_PMCR_P		(1 << 1) /* Reset all counters */
> -#define ARMV8_PMCR_C		(1 << 2) /* Cycle counter reset */
> -#define ARMV8_PMCR_D		(1 << 3) /* CCNT counts every 64th cpu cycle */
> -#define ARMV8_PMCR_X		(1 << 4) /* Export to ETM */
> -#define ARMV8_PMCR_DP		(1 << 5) /* Disable CCNT if non-invasive debug*/
> -#define	ARMV8_PMCR_N_SHIFT	11	 /* Number of counters supported */
> -#define	ARMV8_PMCR_N_MASK	0x1f
> -#define	ARMV8_PMCR_MASK		0x3f	 /* Mask for writable bits */
> -
> -/*
> - * PMOVSR: counters overflow flag status reg
> - */
> -#define	ARMV8_OVSR_MASK		0xffffffff	/* Mask for writable bits */
> -#define	ARMV8_OVERFLOWED_MASK	ARMV8_OVSR_MASK
> -
> -/*
> - * PMXEVTYPER: Event selection reg
> - */
> -#define	ARMV8_EVTYPE_MASK	0xc80003ff	/* Mask for writable bits */
> -#define	ARMV8_EVTYPE_EVENT	0x3ff		/* Mask for EVENT bits */
> -
> -/*
> - * Event filters for PMUv3
> - */
> -#define	ARMV8_EXCLUDE_EL1	(1 << 31)
> -#define	ARMV8_EXCLUDE_EL0	(1 << 30)
> -#define	ARMV8_INCLUDE_EL2	(1 << 27)
> -
>  static inline u32 armv8pmu_pmcr_read(void)
>  {
>  	u32 val;
> 

Thanks,

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

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

* Re: [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h
  2015-12-15 11:34     ` Marc Zyngier
@ 2015-12-15 11:44       ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15 11:44 UTC (permalink / raw)
  To: Marc Zyngier, Shannon Zhao, kvmarm, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel



On 2015/12/15 19:34, Marc Zyngier wrote:
> On 15/12/15 08:49, Shannon Zhao wrote:
>> From: Shannon Zhao <shannon.zhao@linaro.org>
>>
>> To use the ARMv8 PMU related register defines from the KVM code,
>> we move the relevant definitions to asm/pmu.h header file.
>>
>> Signed-off-by: Anup Patel <anup.patel@linaro.org>
>> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
>> ---
>>   arch/arm64/include/asm/pmu.h   | 64 ++++++++++++++++++++++++++++++++++++++++++
>>   arch/arm64/kernel/perf_event.c | 36 +-----------------------
>>   2 files changed, 65 insertions(+), 35 deletions(-)
>>   create mode 100644 arch/arm64/include/asm/pmu.h
>>
>> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
>> new file mode 100644
>> index 0000000..4264ea0
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/pmu.h
>> @@ -0,0 +1,64 @@
>> +/*
>> + * Copyright (C) 2015 Linaro Ltd, Shannon Zhao
>
> Erm, not quite. You're simply moving existing code from one file to
> another. That doesn't change the copyright of said code, which reads:
>
>   * PMU support
>   *
>   * Copyright (C) 2012 ARM Limited
>   * Author: Will Deacon <will.deacon@arm.com>
>
> Please keep this mention in place.
>
Sure, will fix this. Thanks.

-- 
Shannon

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

* [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h
@ 2015-12-15 11:44       ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15 11:44 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/15 19:34, Marc Zyngier wrote:
> On 15/12/15 08:49, Shannon Zhao wrote:
>> From: Shannon Zhao <shannon.zhao@linaro.org>
>>
>> To use the ARMv8 PMU related register defines from the KVM code,
>> we move the relevant definitions to asm/pmu.h header file.
>>
>> Signed-off-by: Anup Patel <anup.patel@linaro.org>
>> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
>> ---
>>   arch/arm64/include/asm/pmu.h   | 64 ++++++++++++++++++++++++++++++++++++++++++
>>   arch/arm64/kernel/perf_event.c | 36 +-----------------------
>>   2 files changed, 65 insertions(+), 35 deletions(-)
>>   create mode 100644 arch/arm64/include/asm/pmu.h
>>
>> diff --git a/arch/arm64/include/asm/pmu.h b/arch/arm64/include/asm/pmu.h
>> new file mode 100644
>> index 0000000..4264ea0
>> --- /dev/null
>> +++ b/arch/arm64/include/asm/pmu.h
>> @@ -0,0 +1,64 @@
>> +/*
>> + * Copyright (C) 2015 Linaro Ltd, Shannon Zhao
>
> Erm, not quite. You're simply moving existing code from one file to
> another. That doesn't change the copyright of said code, which reads:
>
>   * PMU support
>   *
>   * Copyright (C) 2012 ARM Limited
>   * Author: Will Deacon <will.deacon@arm.com>
>
> Please keep this mention in place.
>
Sure, will fix this. Thanks.

-- 
Shannon

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

* Re: [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 13:43     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 13:43 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
> which is mapped to PMEVTYPERn or PMCCFILTR.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When writing to these registers, create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e043224..c52ff15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> +	u64 pmcr, val;
> +
> +	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> +	if (idx >= val && idx != ARMV8_CYCLE_IDX)
> +		return false;
> +
> +	return true;
> +}
> +
> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			       const struct sys_reg_desc *r)
> +{
> +	u64 idx, reg;
> +
> +	if (r->CRn == 9) {
> +		/* PMXEVTYPER_EL0 */
> +		reg = 0;
> +	} else {
> +		if (!p->is_aarch32) {
> +			/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
> +			reg = r->reg;
> +		} else {
> +			if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
> +				reg = PMCCFILTR_EL0;
> +			} else {
> +				reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);

Shouldn't that be "((r->CRm & 3) << 3) | (r->Op2 & 7)"? Otherwise reg is
always 0.

Thanks,

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

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

* [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
@ 2015-12-15 13:43     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 13:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
> which is mapped to PMEVTYPERn or PMCCFILTR.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When writing to these registers, create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e043224..c52ff15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> +	u64 pmcr, val;
> +
> +	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> +	if (idx >= val && idx != ARMV8_CYCLE_IDX)
> +		return false;
> +
> +	return true;
> +}
> +
> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			       const struct sys_reg_desc *r)
> +{
> +	u64 idx, reg;
> +
> +	if (r->CRn == 9) {
> +		/* PMXEVTYPER_EL0 */
> +		reg = 0;
> +	} else {
> +		if (!p->is_aarch32) {
> +			/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
> +			reg = r->reg;
> +		} else {
> +			if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
> +				reg = PMCCFILTR_EL0;
> +			} else {
> +				reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);

Shouldn't that be "((r->CRm & 3) << 3) | (r->Op2 & 7)"? Otherwise reg is
always 0.

Thanks,

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

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

* Re: [PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 13:44     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 13:44 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
> is mapped to PMEVCNTRn.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When reading these registers, return the sum of register value and the
> value perf event counts.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 136 ++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 132 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c52ff15..dc6bb26 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -566,6 +566,55 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
> +			      struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	u64 idx, reg, val;
> +
> +	if (!p->is_aarch32) {
> +		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
> +			/* PMXEVCNTR_EL0 */
> +			reg = 0;
> +		else
> +			/* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
> +			reg = r->reg;
> +	} else {
> +		if (r->CRn == 9 && r->CRm == 13) {
> +			reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
> +		} else {
> +			reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);

Same bug as the previous patch.

Thanks,

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

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

* [PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register
@ 2015-12-15 13:44     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 13:44 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> These kind of registers include PMEVCNTRn, PMCCNTR and PMXEVCNTR which
> is mapped to PMEVCNTRn.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When reading these registers, return the sum of register value and the
> value perf event counts.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 136 ++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 132 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c52ff15..dc6bb26 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -566,6 +566,55 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
> +			      struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	u64 idx, reg, val;
> +
> +	if (!p->is_aarch32) {
> +		if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 2)
> +			/* PMXEVCNTR_EL0 */
> +			reg = 0;
> +		else
> +			/* PMEVCNTRn_EL0 or PMCCNTR_EL0 */
> +			reg = r->reg;
> +	} else {
> +		if (r->CRn == 9 && r->CRm == 13) {
> +			reg = (r->Op2 & 2) ? 0 : PMCCNTR_EL0;
> +		} else {
> +			reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);

Same bug as the previous patch.

Thanks,

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

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

* Re: [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 13:56     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 13:56 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: wei, hangaohuai, kvm, will.deacon, peter.huangpeng, cov,
	alex.bennee, linux-arm-kernel, shannon.zhao

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMCNTENSET or PMCNTENCLR register.
> 
> When writing to PMCNTENSET, call perf_event_enable to enable the perf
> event. When writing to PMCNTENCLR, call perf_event_disable to disable
> the perf event.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 41 +++++++++++++++++++++++++++++++----
>  include/kvm/arm_pmu.h     |  4 ++++
>  virt/kvm/arm/pmu.c        | 55 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 96 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index dc6bb26..f216da7 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>  	return true;
>  }
>  
> +static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
> +{
> +	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
> +
> +	val &= ARMV8_PMCR_N_MASK;
> +	return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
> +}
> +
> +static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	u64 val, mask;
> +
> +	mask = kvm_pmu_valid_counter_mask(vcpu);
> +	if (p->is_write) {
> +		val = p->regval & mask;
> +		if (r->Op2 & 0x1) {
> +			/* accessing PMCNTENSET_EL0 */
> +			vcpu_sys_reg(vcpu, r->reg) |= val;
> +			kvm_pmu_enable_counter(vcpu, val);
> +		} else {
> +			/* accessing PMCNTENCLR_EL0 */
> +			vcpu_sys_reg(vcpu, r->reg) &= mask;
> +			vcpu_sys_reg(vcpu, r->reg) &= ~val;
> +			kvm_pmu_disable_counter(vcpu, val);
> +		}
> +	} else {
> +		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> +	}
> +
> +	return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  access_pmcr, reset_pmcr, PMCR_EL0, },
>  	/* PMCNTENSET_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
> -	  trap_raz_wi },
> +	  access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
>  	/* PMCNTENCLR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
> -	  trap_raz_wi },
> +	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
>  	/* PMOVSCLR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
>  	  trap_raz_wi },
> @@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>  
>  	/* PMU */
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
> -	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
> -	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 14bedb0..43c4117 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -36,6 +36,8 @@ struct kvm_pmu {
>  };
>  
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx);
>  #else
> @@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
>  	return 0;
>  }
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index b107fb8..94bff0e 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_enable_counter - enable selected PMU counter
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMCNTENSET register
> + *
> + * Call perf_event_enable to start counting the perf event
> + */
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	int i;
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	struct kvm_pmc *pmc;
> +
> +	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) || !val)
> +		return;
> +
> +	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
> +		if (!((val >> i) & 0x1))
> +			continue;

nit: it is slightly more readable to have "if (!(val & (1 << i)))

> +
> +		pmc = &pmu->pmc[i];
> +		if (pmc->perf_event) {
> +			perf_event_enable(pmc->perf_event);
> +			if (pmc->perf_event->state != PERF_EVENT_STATE_ACTIVE)
> +				kvm_debug("fail to enable perf event\n");
> +		}
> +	}
> +}
> +
> +/**
> + * kvm_pmu_disable_counter - disable selected PMU counter
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMCNTENCLR register
> + *
> + * Call perf_event_disable to stop counting the perf event
> + */
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	int i;
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	struct kvm_pmc *pmc;
> +
> +	if (!val)
> +		return;
> +
> +	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
> +		if (!((val >> i) & 0x1))

Same here.

> +			continue;
> +
> +		pmc = &pmu->pmc[i];
> +		if (pmc->perf_event)
> +			perf_event_disable(pmc->perf_event);
> +	}
> +}
> +
> +/**
>   * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>   * @vcpu: The vcpu pointer
>   * @data: The data guest writes to PMXEVTYPER_EL0
> 

Thanks,

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

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

* [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register
@ 2015-12-15 13:56     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 13:56 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Since the reset value of PMCNTENSET and PMCNTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMCNTENSET or PMCNTENCLR register.
> 
> When writing to PMCNTENSET, call perf_event_enable to enable the perf
> event. When writing to PMCNTENCLR, call perf_event_disable to disable
> the perf event.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 41 +++++++++++++++++++++++++++++++----
>  include/kvm/arm_pmu.h     |  4 ++++
>  virt/kvm/arm/pmu.c        | 55 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 96 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index dc6bb26..f216da7 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -615,6 +615,39 @@ static bool access_pmu_evcntr(struct kvm_vcpu *vcpu,
>  	return true;
>  }
>  
> +static inline u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu)
> +{
> +	u64 val = vcpu_sys_reg(vcpu, PMCR_EL0) >> ARMV8_PMCR_N_SHIFT;
> +
> +	val &= ARMV8_PMCR_N_MASK;
> +	return GENMASK(val - 1, 0) | BIT(ARMV8_CYCLE_IDX);
> +}
> +
> +static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	u64 val, mask;
> +
> +	mask = kvm_pmu_valid_counter_mask(vcpu);
> +	if (p->is_write) {
> +		val = p->regval & mask;
> +		if (r->Op2 & 0x1) {
> +			/* accessing PMCNTENSET_EL0 */
> +			vcpu_sys_reg(vcpu, r->reg) |= val;
> +			kvm_pmu_enable_counter(vcpu, val);
> +		} else {
> +			/* accessing PMCNTENCLR_EL0 */
> +			vcpu_sys_reg(vcpu, r->reg) &= mask;
> +			vcpu_sys_reg(vcpu, r->reg) &= ~val;
> +			kvm_pmu_disable_counter(vcpu, val);
> +		}
> +	} else {
> +		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> +	}
> +
> +	return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -816,10 +849,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  access_pmcr, reset_pmcr, PMCR_EL0, },
>  	/* PMCNTENSET_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
> -	  trap_raz_wi },
> +	  access_pmcntenset, reset_unknown, PMCNTENSET_EL0 },
>  	/* PMCNTENCLR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
> -	  trap_raz_wi },
> +	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
>  	/* PMOVSCLR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
>  	  trap_raz_wi },
> @@ -1161,8 +1194,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>  
>  	/* PMU */
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
> -	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), trap_raz_wi },
> -	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), trap_raz_wi },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 14bedb0..43c4117 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -36,6 +36,8 @@ struct kvm_pmu {
>  };
>  
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx);
>  #else
> @@ -46,6 +48,8 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
>  	return 0;
>  }
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index b107fb8..94bff0e 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -75,6 +75,61 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_enable_counter - enable selected PMU counter
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMCNTENSET register
> + *
> + * Call perf_event_enable to start counting the perf event
> + */
> +void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	int i;
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	struct kvm_pmc *pmc;
> +
> +	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E) || !val)
> +		return;
> +
> +	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
> +		if (!((val >> i) & 0x1))
> +			continue;

nit: it is slightly more readable to have "if (!(val & (1 << i)))

> +
> +		pmc = &pmu->pmc[i];
> +		if (pmc->perf_event) {
> +			perf_event_enable(pmc->perf_event);
> +			if (pmc->perf_event->state != PERF_EVENT_STATE_ACTIVE)
> +				kvm_debug("fail to enable perf event\n");
> +		}
> +	}
> +}
> +
> +/**
> + * kvm_pmu_disable_counter - disable selected PMU counter
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMCNTENCLR register
> + *
> + * Call perf_event_disable to stop counting the perf event
> + */
> +void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	int i;
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	struct kvm_pmc *pmc;
> +
> +	if (!val)
> +		return;
> +
> +	for (i = 0; i < ARMV8_MAX_COUNTERS; i++) {
> +		if (!((val >> i) & 0x1))

Same here.

> +			continue;
> +
> +		pmc = &pmu->pmc[i];
> +		if (pmc->perf_event)
> +			perf_event_disable(pmc->perf_event);
> +	}
> +}
> +
> +/**
>   * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>   * @vcpu: The vcpu pointer
>   * @data: The data guest writes to PMXEVTYPER_EL0
> 

Thanks,

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

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

* Re: [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 14:02     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:02 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMINTENSET or PMINTENCLR register.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 29 +++++++++++++++++++++++++----
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f216da7..594e53f 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> +	if (p->is_write) {
> +		if (r->Op2 & 0x1) {
> +			/* accessing PMINTENSET_EL1 */
> +			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
> +		} else {
> +			/* accessing PMINTENCLR_EL1 */
> +			vcpu_sys_reg(vcpu, r->reg) &= mask;
> +			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

This looks wrong. The first line doesn't have any effect (you shouldn't
be able to set bits that are not in the mask the first place). I'd
prefer something like:

		vcpu_sys_reg(vcpu, r->reg) &= ~(p->regval & mask);

which is symmetrical to the SET operator.

> +		}
> +	} else {
> +		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> +	}
> +
> +	return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  
>  	/* PMINTENSET_EL1 */
>  	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
> -	  trap_raz_wi },
> +	  access_pmintenset, reset_unknown, PMINTENSET_EL1 },
>  	/* PMINTENCLR_EL1 */
>  	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
> -	  trap_raz_wi },
> +	  access_pmintenset, NULL, PMINTENSET_EL1 },
>  
>  	/* MAIR_EL1 */
>  	{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
> @@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
>  	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
> -	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
> -	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
> +	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
> +	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
>  
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> 

Thanks,

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

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

* [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register
@ 2015-12-15 14:02     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Since the reset value of PMINTENSET and PMINTENCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMINTENSET or PMINTENCLR register.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 29 +++++++++++++++++++++++++----
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index f216da7..594e53f 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -648,6 +648,27 @@ static bool access_pmcntenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
> +{
> +	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> +	if (p->is_write) {
> +		if (r->Op2 & 0x1) {
> +			/* accessing PMINTENSET_EL1 */
> +			vcpu_sys_reg(vcpu, r->reg) |= (p->regval & mask);
> +		} else {
> +			/* accessing PMINTENCLR_EL1 */
> +			vcpu_sys_reg(vcpu, r->reg) &= mask;
> +			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

This looks wrong. The first line doesn't have any effect (you shouldn't
be able to set bits that are not in the mask the first place). I'd
prefer something like:

		vcpu_sys_reg(vcpu, r->reg) &= ~(p->regval & mask);

which is symmetrical to the SET operator.

> +		}
> +	} else {
> +		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> +	}
> +
> +	return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -806,10 +827,10 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  
>  	/* PMINTENSET_EL1 */
>  	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
> -	  trap_raz_wi },
> +	  access_pmintenset, reset_unknown, PMINTENSET_EL1 },
>  	/* PMINTENCLR_EL1 */
>  	{ Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
> -	  trap_raz_wi },
> +	  access_pmintenset, NULL, PMINTENSET_EL1 },
>  
>  	/* MAIR_EL1 */
>  	{ Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
> @@ -1204,8 +1225,8 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(13), Op2( 1), access_pmu_evtyper },
>  	{ Op1( 0), CRn( 9), CRm(13), Op2( 2), access_pmu_evcntr },
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
> -	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), trap_raz_wi },
> -	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), trap_raz_wi },
> +	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
> +	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
>  
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> 

Thanks,

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

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

* Re: [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 14:06     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:06 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: wei, hangaohuai, kvm, will.deacon, peter.huangpeng, cov,
	alex.bennee, linux-arm-kernel, shannon.zhao

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMOVSSET or PMOVSCLR register.
> 
> When writing non-zero value to PMOVSSET, pend PMU interrupt.

This comment doesn't match the code anymore

> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 28 +++++++++++++++++++++++++---
>  include/kvm/arm_pmu.h     |  2 ++
>  virt/kvm/arm/pmu.c        | 20 ++++++++++++++++++++
>  3 files changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 594e53f..d1926c4 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> +	if (p->is_write) {
> +		if (r->CRm & 0x2) {
> +			/* accessing PMOVSSET_EL0 */
> +			kvm_pmu_overflow_set(vcpu, p->regval & mask);
> +		} else {
> +			/* accessing PMOVSCLR_EL0 */
> +			vcpu_sys_reg(vcpu, r->reg) &= mask;
> +			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

Same as the previous patch.

> +		}
> +	} else {
> +		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> +	}
> +
> +	return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
>  	/* PMOVSCLR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> -	  trap_raz_wi },
> +	  access_pmovsset, NULL, PMOVSSET_EL0 },
>  	/* PMSWINC_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
>  	  trap_raz_wi },
> @@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  trap_raz_wi },
>  	/* PMOVSSET_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
> -	  trap_raz_wi },
> +	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
>  
>  	/* TPIDR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
> @@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
> -	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> @@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
> +	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
>  
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 43c4117..93aea6a 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -38,6 +38,7 @@ struct kvm_pmu {
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx);
>  #else
> @@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  }
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 94bff0e..861471d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -130,6 +130,26 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
>  }
>  
>  /**
> + * kvm_pmu_overflow_set - set PMU overflow interrupt
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMOVSSET register
> + */
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	u64 reg;
> +
> +	if (val == 0)
> +		return;
> +
> +	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= val;
> +	reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0)
> +	      & vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
> +	      & vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> +	if (reg != 0)
> +		kvm_vcpu_kick(vcpu);
> +}
> +
> +/**
>   * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>   * @vcpu: The vcpu pointer
>   * @data: The data guest writes to PMXEVTYPER_EL0
> 

Thanks,

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

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

* [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register
@ 2015-12-15 14:06     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:06 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Since the reset value of PMOVSSET and PMOVSCLR is UNKNOWN, use
> reset_unknown for its reset handler. Add a handler to emulate writing
> PMOVSSET or PMOVSCLR register.
> 
> When writing non-zero value to PMOVSSET, pend PMU interrupt.

This comment doesn't match the code anymore

> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 28 +++++++++++++++++++++++++---
>  include/kvm/arm_pmu.h     |  2 ++
>  virt/kvm/arm/pmu.c        | 20 ++++++++++++++++++++
>  3 files changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 594e53f..d1926c4 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -669,6 +669,27 @@ static bool access_pmintenset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			    const struct sys_reg_desc *r)
> +{
> +	u64 mask = kvm_pmu_valid_counter_mask(vcpu);
> +
> +	if (p->is_write) {
> +		if (r->CRm & 0x2) {
> +			/* accessing PMOVSSET_EL0 */
> +			kvm_pmu_overflow_set(vcpu, p->regval & mask);
> +		} else {
> +			/* accessing PMOVSCLR_EL0 */
> +			vcpu_sys_reg(vcpu, r->reg) &= mask;
> +			vcpu_sys_reg(vcpu, r->reg) &= ~p->regval;

Same as the previous patch.

> +		}
> +	} else {
> +		p->regval = vcpu_sys_reg(vcpu, r->reg) & mask;
> +	}
> +
> +	return true;
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -876,7 +897,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  access_pmcntenset, NULL, PMCNTENSET_EL0 },
>  	/* PMOVSCLR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
> -	  trap_raz_wi },
> +	  access_pmovsset, NULL, PMOVSSET_EL0 },
>  	/* PMSWINC_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
>  	  trap_raz_wi },
> @@ -903,7 +924,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  trap_raz_wi },
>  	/* PMOVSSET_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
> -	  trap_raz_wi },
> +	  access_pmovsset, reset_unknown, PMOVSSET_EL0 },
>  
>  	/* TPIDR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
> @@ -1217,7 +1238,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 0), access_pmcr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
> -	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), trap_raz_wi },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> @@ -1227,6 +1248,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 0), trap_raz_wi },
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 1), access_pmintenset },
>  	{ Op1( 0), CRn( 9), CRm(14), Op2( 2), access_pmintenset },
> +	{ Op1( 0), CRn( 9), CRm(14), Op2( 3), access_pmovsset },
>  
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, c10_PRRR },
>  	{ Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 43c4117..93aea6a 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -38,6 +38,7 @@ struct kvm_pmu {
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx);
>  #else
> @@ -50,6 +51,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  }
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 94bff0e..861471d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -130,6 +130,26 @@ void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val)
>  }
>  
>  /**
> + * kvm_pmu_overflow_set - set PMU overflow interrupt
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMOVSSET register
> + */
> +void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	u64 reg;
> +
> +	if (val == 0)
> +		return;
> +
> +	vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= val;
> +	reg = vcpu_sys_reg(vcpu, PMOVSSET_EL0)
> +	      & vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
> +	      & vcpu_sys_reg(vcpu, PMINTENSET_EL1);
> +	if (reg != 0)
> +		kvm_vcpu_kick(vcpu);
> +}
> +
> +/**
>   * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>   * @vcpu: The vcpu pointer
>   * @data: The data guest writes to PMXEVTYPER_EL0
> 

Thanks,

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

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

* Re: [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 14:20     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:20 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Add access handler which gets host value of PMCEID0 or PMCEID1 when
> guest access these registers. Writing action to PMCEID0 or PMCEID1 is
> ignored.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++----
>  1 file changed, 22 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c21f91b..e043224 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -486,6 +486,24 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			  const struct sys_reg_desc *r)
> +{
> +	u64 pmceid;
> +
> +	if (p->is_write)
> +		return write_to_read_only(vcpu, p);

This register in UNDEFINED in that case. You should call
kvm_inject_undefined() for that vcpu and return.

Thanks,

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

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

* [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register
@ 2015-12-15 14:20     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Add access handler which gets host value of PMCEID0 or PMCEID1 when
> guest access these registers. Writing action to PMCEID0 or PMCEID1 is
> ignored.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 26 ++++++++++++++++++++++----
>  1 file changed, 22 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c21f91b..e043224 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -486,6 +486,24 @@ static bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			  const struct sys_reg_desc *r)
> +{
> +	u64 pmceid;
> +
> +	if (p->is_write)
> +		return write_to_read_only(vcpu, p);

This register in UNDEFINED in that case. You should call
kvm_inject_undefined() for that vcpu and return.

Thanks,

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

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

* Re: [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 14:26     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:26 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
> which is mapped to PMEVTYPERn or PMCCFILTR.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When writing to these registers, create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e043224..c52ff15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> +	u64 pmcr, val;
> +
> +	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> +	if (idx >= val && idx != ARMV8_CYCLE_IDX)
> +		return false;
> +
> +	return true;
> +}
> +
> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			       const struct sys_reg_desc *r)
> +{
> +	u64 idx, reg;
> +
> +	if (r->CRn == 9) {
> +		/* PMXEVTYPER_EL0 */
> +		reg = 0;
> +	} else {
> +		if (!p->is_aarch32) {
> +			/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
> +			reg = r->reg;
> +		} else {
> +			if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
> +				reg = PMCCFILTR_EL0;
> +			} else {
> +				reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
> +				reg += PMEVTYPER0_EL0;
> +			}
> +		}
> +	}
> +
> +	switch (reg) {
> +	case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
> +		idx = reg - PMEVTYPER0_EL0;
> +		break;
> +	case PMCCFILTR_EL0:
> +		idx = ARMV8_CYCLE_IDX;
> +		break;
> +	default:
> +		/* PMXEVTYPER_EL0 */
> +		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
> +		if (!pmu_counter_idx_valid(vcpu, idx))
> +			return true;

Shouldn't you check the validity of the index in the first case as well?

Thanks,

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

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

* [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
@ 2015-12-15 14:26     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:26 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER
> which is mapped to PMEVTYPERn or PMCCFILTR.
> 
> The access handler translates all aarch32 register offsets to aarch64
> ones and uses vcpu_sys_reg() to access their values to avoid taking care
> of big endian.
> 
> When writing to these registers, create a perf_event for the selected
> event type.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 154 +++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e043224..c52ff15 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx)
> +{
> +	u64 pmcr, val;
> +
> +	pmcr = vcpu_sys_reg(vcpu, PMCR_EL0);
> +	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> +	if (idx >= val && idx != ARMV8_CYCLE_IDX)
> +		return false;
> +
> +	return true;
> +}
> +
> +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			       const struct sys_reg_desc *r)
> +{
> +	u64 idx, reg;
> +
> +	if (r->CRn == 9) {
> +		/* PMXEVTYPER_EL0 */
> +		reg = 0;
> +	} else {
> +		if (!p->is_aarch32) {
> +			/* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */
> +			reg = r->reg;
> +		} else {
> +			if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) {
> +				reg = PMCCFILTR_EL0;
> +			} else {
> +				reg = ((r->CRm & 3) << 3) & (r->Op2 & 7);
> +				reg += PMEVTYPER0_EL0;
> +			}
> +		}
> +	}
> +
> +	switch (reg) {
> +	case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0:
> +		idx = reg - PMEVTYPER0_EL0;
> +		break;
> +	case PMCCFILTR_EL0:
> +		idx = ARMV8_CYCLE_IDX;
> +		break;
> +	default:
> +		/* PMXEVTYPER_EL0 */
> +		idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK;
> +		if (!pmu_counter_idx_valid(vcpu, idx))
> +			return true;

Shouldn't you check the validity of the index in the first case as well?

Thanks,

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

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

* Re: [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 14:36     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:36 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Add access handler which emulates writing and reading PMSWINC
> register and add support for creating software increment event.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 14 +++++++++++++-
>  include/kvm/arm_pmu.h     |  2 ++
>  virt/kvm/arm/pmu.c        | 32 ++++++++++++++++++++++++++++++++
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index d1926c4..f09e500 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			   const struct sys_reg_desc *r)
> +{
> +	if (p->is_write) {
> +		kvm_pmu_software_increment(vcpu, p->regval);

Shouldn't you filter this with valid counter mask?

> +		return true;
> +	} else {
> +		return read_zero(vcpu, p);

Mark just mentioned to me that reading from this register is UNDEFINED.
Which means you should generate an exception into the guest by calling
kvm_inject_undefined() for that vcpu.

> +	}
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  access_pmovsset, NULL, PMOVSSET_EL0 },
>  	/* PMSWINC_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> -	  trap_raz_wi },
> +	  access_pmswinc, reset_unknown, PMSWINC_EL0 },
>  	/* PMSELR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
>  	  access_pmselr, reset_unknown, PMSELR_EL0 },
> @@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 93aea6a..f5888eb 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx);
>  #else
> @@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 861471d..01af727 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
>  }
>  
>  /**
> + * kvm_pmu_software_increment - do software increment
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMSWINC register
> + */
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	int i;
> +	u64 type, enable, reg;
> +
> +	if (val == 0)
> +		return;
> +
> +	for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
> +		if (!((val >> i) & 0x1))

Same comment as for the other patches.

> +			continue;
> +		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +		       & ARMV8_EVTYPE_EVENT;
> +		enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +		if ((type == 0) && ((enable >> i) & 0x1)) {
> +			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
> +			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
> +			if ((reg & 0xFFFFFFFF) == 0)
> +				kvm_pmu_overflow_set(vcpu, BIT(i));

The increment handling is not very nice, as you end-up with stuff in the
upper 32bit... How about:

	reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
	reg = lower_32bit(reg);
	vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
	if (!reg)
		kvm_pmu_overflow_set(vcpu, BIT(i));

> +		}
> +	}
> +}
> +
> +/**
>   * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>   * @vcpu: The vcpu pointer
>   * @data: The data guest writes to PMXEVTYPER_EL0
> @@ -171,6 +199,10 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  	kvm_pmu_stop_counter(vcpu, pmc);
>  	eventsel = data & ARMV8_EVTYPE_EVENT;
>  
> +	/* For software increment event it does't need to create perf event */
> +	if (eventsel == 0)
> +		return;
> +
>  	memset(&attr, 0, sizeof(struct perf_event_attr));
>  	attr.type = PERF_TYPE_RAW;
>  	attr.size = sizeof(attr);
> 

Thanks,

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

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

* [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register
@ 2015-12-15 14:36     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Add access handler which emulates writing and reading PMSWINC
> register and add support for creating software increment event.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 14 +++++++++++++-
>  include/kvm/arm_pmu.h     |  2 ++
>  virt/kvm/arm/pmu.c        | 32 ++++++++++++++++++++++++++++++++
>  3 files changed, 47 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index d1926c4..f09e500 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -690,6 +690,17 @@ static bool access_pmovsset(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	return true;
>  }
>  
> +static bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
> +			   const struct sys_reg_desc *r)
> +{
> +	if (p->is_write) {
> +		kvm_pmu_software_increment(vcpu, p->regval);

Shouldn't you filter this with valid counter mask?

> +		return true;
> +	} else {
> +		return read_zero(vcpu, p);

Mark just mentioned to me that reading from this register is UNDEFINED.
Which means you should generate an exception into the guest by calling
kvm_inject_undefined() for that vcpu.

> +	}
> +}
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
>  #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
>  	/* DBGBVRn_EL1 */						\
> @@ -900,7 +911,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	  access_pmovsset, NULL, PMOVSSET_EL0 },
>  	/* PMSWINC_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
> -	  trap_raz_wi },
> +	  access_pmswinc, reset_unknown, PMSWINC_EL0 },
>  	/* PMSELR_EL0 */
>  	{ Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
>  	  access_pmselr, reset_unknown, PMSELR_EL0 },
> @@ -1239,6 +1250,7 @@ static const struct sys_reg_desc cp15_regs[] = {
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 1), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 2), access_pmcntenset },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 3), access_pmovsset },
> +	{ Op1( 0), CRn( 9), CRm(12), Op2( 4), access_pmswinc },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 5), access_pmselr },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 6), access_pmceid },
>  	{ Op1( 0), CRn( 9), CRm(12), Op2( 7), access_pmceid },
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 93aea6a..f5888eb 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -39,6 +39,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val);
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx);
>  #else
> @@ -52,6 +53,7 @@ u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val) {}
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val) {}
>  void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  				    u64 select_idx) {}
>  #endif
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index 861471d..01af727 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -150,6 +150,34 @@ void kvm_pmu_overflow_set(struct kvm_vcpu *vcpu, u64 val)
>  }
>  
>  /**
> + * kvm_pmu_software_increment - do software increment
> + * @vcpu: The vcpu pointer
> + * @val: the value guest writes to PMSWINC register
> + */
> +void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
> +{
> +	int i;
> +	u64 type, enable, reg;
> +
> +	if (val == 0)
> +		return;
> +
> +	for (i = 0; i < ARMV8_CYCLE_IDX; i++) {
> +		if (!((val >> i) & 0x1))

Same comment as for the other patches.

> +			continue;
> +		type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
> +		       & ARMV8_EVTYPE_EVENT;
> +		enable = vcpu_sys_reg(vcpu, PMCNTENSET_EL0);
> +		if ((type == 0) && ((enable >> i) & 0x1)) {
> +			vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i)++;
> +			reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i);
> +			if ((reg & 0xFFFFFFFF) == 0)
> +				kvm_pmu_overflow_set(vcpu, BIT(i));

The increment handling is not very nice, as you end-up with stuff in the
upper 32bit... How about:

	reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
	reg = lower_32bit(reg);
	vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) = reg;
	if (!reg)
		kvm_pmu_overflow_set(vcpu, BIT(i));

> +		}
> +	}
> +}
> +
> +/**
>   * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>   * @vcpu: The vcpu pointer
>   * @data: The data guest writes to PMXEVTYPER_EL0
> @@ -171,6 +199,10 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  	kvm_pmu_stop_counter(vcpu, pmc);
>  	eventsel = data & ARMV8_EVTYPE_EVENT;
>  
> +	/* For software increment event it does't need to create perf event */
> +	if (eventsel == 0)
> +		return;
> +
>  	memset(&attr, 0, sizeof(struct perf_event_attr));
>  	attr.type = PERF_TYPE_RAW;
>  	attr.size = sizeof(attr);
> 

Thanks,

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

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

* Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 14:58     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:58 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel, shannon.zhao

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
> 
> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
> accessed from EL0. Add some check helpers to handle the access from EL0.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 119 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b2ccc25..bad3dfd 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	vcpu_sys_reg(vcpu, r->reg) = val;
>  }
>  
> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
> +}

Please add #defines for the PMUSERNR_EL0 bits.

> +
>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  			const struct sys_reg_desc *r)
>  {
>  	u64 val;
> +	bool unaccessible = pmu_access_el0_disabled(vcpu);
>  
>  	if (p->is_write) {
> +		if (unaccessible)
> +			return ignore_write(vcpu, p);
> +

This is not how this is supposed to work. If EL0 is denied access to the
PMU, you must inject an exception into EL1 for it to handle the fault.
The code should reflect the flow described at D5.11.2 in the ARM ARM.

This whole patch needs to be revisited, I'm afraid.

Thanks,

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

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

* [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
@ 2015-12-15 14:58     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
> 
> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
> accessed from EL0. Add some check helpers to handle the access from EL0.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 119 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b2ccc25..bad3dfd 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	vcpu_sys_reg(vcpu, r->reg) = val;
>  }
>  
> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
> +}
> +
> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
> +{
> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
> +
> +	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
> +}

Please add #defines for the PMUSERNR_EL0 bits.

> +
>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  			const struct sys_reg_desc *r)
>  {
>  	u64 val;
> +	bool unaccessible = pmu_access_el0_disabled(vcpu);
>  
>  	if (p->is_write) {
> +		if (unaccessible)
> +			return ignore_write(vcpu, p);
> +

This is not how this is supposed to work. If EL0 is denied access to the
PMU, you must inject an exception into EL1 for it to handle the fault.
The code should reflect the flow described at D5.11.2 in the ARM ARM.

This whole patch needs to be revisited, I'm afraid.

Thanks,

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

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

* Re: [PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 15:19     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:19 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> When calling perf_event_create_kernel_counter to create perf_event,
> assign a overflow handler. Then when the perf event overflows, set the
> corresponding bit of guest PMOVSSET register. If this counter is enabled
> and its interrupt is enabled as well, kick the vcpu to sync the
> interrupt.
> 
> On VM entry, if there is counter overflowed, inject the interrupt with
> the level set to 1. Otherwise, inject the interrupt with the level set
> to 0.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm/kvm/arm.c    |  2 ++
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c    | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index e06fd29..cd696ef 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -28,6 +28,7 @@
>  #include <linux/sched.h>
>  #include <linux/kvm.h>
>  #include <trace/events/kvm.h>
> +#include <kvm/arm_pmu.h>
>  
>  #define CREATE_TRACE_POINTS
>  #include "trace.h"
> @@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		 * non-preemptible context.
>  		 */
>  		preempt_disable();
> +		kvm_pmu_flush_hwstate(vcpu);
>  		kvm_timer_flush_hwstate(vcpu);
>  		kvm_vgic_flush_hwstate(vcpu);
>  
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 25b5f98..732ccaf 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -35,6 +35,7 @@ struct kvm_pmu {
>  	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
>  };
>  
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
> @@ -47,6 +48,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
>  struct kvm_pmu {
>  };
>  
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
>  	return 0;
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index e664721..eff5b19 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -21,6 +21,7 @@
>  #include <linux/perf_event.h>
>  #include <asm/kvm_emulate.h>
>  #include <kvm/arm_pmu.h>
> +#include <kvm/arm_vgic.h>
>  
>  /**
>   * kvm_pmu_get_counter_value - get PMU counter value
> @@ -75,6 +76,56 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_flush_hwstate - flush pmu state to cpu
> + * @vcpu: The vcpu pointer
> + *
> + * Inject virtual PMU IRQ if IRQ is pending for this cpu.
> + */
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	u64 overflow;
> +
> +	if (pmu->irq_num == -1)
> +		return;
> +
> +	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
> +		return;
> +
> +	overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
> +		   & vcpu_sys_reg(vcpu, PMINTENSET_EL1)
> +		   & vcpu_sys_reg(vcpu, PMOVSSET_EL0);

You already have something similar to deal with enabling the overflow
interrupt. You may want to have a common helper.

> +
> +	kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
> +			    overflow ? 1 : 0);

nit: can also be written as !!overflow.

> +}
> +
> +static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
> +{
> +	struct kvm_pmu *pmu;
> +	struct kvm_vcpu_arch *vcpu_arch;
> +
> +	pmc -= pmc->idx;
> +	pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
> +	vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
> +	return container_of(vcpu_arch, struct kvm_vcpu, arch);
> +}
> +
> +/**
> + * When perf event overflows, call kvm_pmu_overflow_set to set overflow status.
> + */
> +static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
> +				  struct perf_sample_data *data,
> +				  struct pt_regs *regs)
> +{
> +	struct kvm_pmc *pmc = perf_event->overflow_handler_context;
> +	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
> +	int idx = pmc->idx;
> +
> +	kvm_pmu_overflow_set(vcpu, BIT(idx));
> +}
> +
> +/**
>   * kvm_pmu_enable_counter - enable selected PMU counter
>   * @vcpu: The vcpu pointer
>   * @val: the value guest writes to PMCNTENSET register
> @@ -258,7 +309,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  	/* The initial sample period (overflow count) of an event. */
>  	attr.sample_period = (-counter) & pmc->bitmask;
>  
> -	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
> +	event = perf_event_create_kernel_counter(&attr, -1, current,
> +						 kvm_pmu_perf_overflow, pmc);
>  	if (IS_ERR(event)) {
>  		printk_once("kvm: pmu event creation failed %ld\n",
>  			    PTR_ERR(event));
> 

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

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

* [PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing
@ 2015-12-15 15:19     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> When calling perf_event_create_kernel_counter to create perf_event,
> assign a overflow handler. Then when the perf event overflows, set the
> corresponding bit of guest PMOVSSET register. If this counter is enabled
> and its interrupt is enabled as well, kick the vcpu to sync the
> interrupt.
> 
> On VM entry, if there is counter overflowed, inject the interrupt with
> the level set to 1. Otherwise, inject the interrupt with the level set
> to 0.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm/kvm/arm.c    |  2 ++
>  include/kvm/arm_pmu.h |  2 ++
>  virt/kvm/arm/pmu.c    | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 57 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
> index e06fd29..cd696ef 100644
> --- a/arch/arm/kvm/arm.c
> +++ b/arch/arm/kvm/arm.c
> @@ -28,6 +28,7 @@
>  #include <linux/sched.h>
>  #include <linux/kvm.h>
>  #include <trace/events/kvm.h>
> +#include <kvm/arm_pmu.h>
>  
>  #define CREATE_TRACE_POINTS
>  #include "trace.h"
> @@ -569,6 +570,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  		 * non-preemptible context.
>  		 */
>  		preempt_disable();
> +		kvm_pmu_flush_hwstate(vcpu);
>  		kvm_timer_flush_hwstate(vcpu);
>  		kvm_vgic_flush_hwstate(vcpu);
>  
> diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h
> index 25b5f98..732ccaf 100644
> --- a/include/kvm/arm_pmu.h
> +++ b/include/kvm/arm_pmu.h
> @@ -35,6 +35,7 @@ struct kvm_pmu {
>  	struct kvm_pmc pmc[ARMV8_MAX_COUNTERS];
>  };
>  
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu);
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
>  void kvm_pmu_disable_counter(struct kvm_vcpu *vcpu, u64 val);
>  void kvm_pmu_enable_counter(struct kvm_vcpu *vcpu, u64 val);
> @@ -47,6 +48,7 @@ void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val);
>  struct kvm_pmu {
>  };
>  
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu) {}
>  u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx)
>  {
>  	return 0;
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index e664721..eff5b19 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -21,6 +21,7 @@
>  #include <linux/perf_event.h>
>  #include <asm/kvm_emulate.h>
>  #include <kvm/arm_pmu.h>
> +#include <kvm/arm_vgic.h>
>  
>  /**
>   * kvm_pmu_get_counter_value - get PMU counter value
> @@ -75,6 +76,56 @@ static void kvm_pmu_stop_counter(struct kvm_vcpu *vcpu, struct kvm_pmc *pmc)
>  }
>  
>  /**
> + * kvm_pmu_flush_hwstate - flush pmu state to cpu
> + * @vcpu: The vcpu pointer
> + *
> + * Inject virtual PMU IRQ if IRQ is pending for this cpu.
> + */
> +void kvm_pmu_flush_hwstate(struct kvm_vcpu *vcpu)
> +{
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	u64 overflow;
> +
> +	if (pmu->irq_num == -1)
> +		return;
> +
> +	if (!(vcpu_sys_reg(vcpu, PMCR_EL0) & ARMV8_PMCR_E))
> +		return;
> +
> +	overflow = vcpu_sys_reg(vcpu, PMCNTENSET_EL0)
> +		   & vcpu_sys_reg(vcpu, PMINTENSET_EL1)
> +		   & vcpu_sys_reg(vcpu, PMOVSSET_EL0);

You already have something similar to deal with enabling the overflow
interrupt. You may want to have a common helper.

> +
> +	kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, pmu->irq_num,
> +			    overflow ? 1 : 0);

nit: can also be written as !!overflow.

> +}
> +
> +static inline struct kvm_vcpu *kvm_pmc_to_vcpu(struct kvm_pmc *pmc)
> +{
> +	struct kvm_pmu *pmu;
> +	struct kvm_vcpu_arch *vcpu_arch;
> +
> +	pmc -= pmc->idx;
> +	pmu = container_of(pmc, struct kvm_pmu, pmc[0]);
> +	vcpu_arch = container_of(pmu, struct kvm_vcpu_arch, pmu);
> +	return container_of(vcpu_arch, struct kvm_vcpu, arch);
> +}
> +
> +/**
> + * When perf event overflows, call kvm_pmu_overflow_set to set overflow status.
> + */
> +static void kvm_pmu_perf_overflow(struct perf_event *perf_event,
> +				  struct perf_sample_data *data,
> +				  struct pt_regs *regs)
> +{
> +	struct kvm_pmc *pmc = perf_event->overflow_handler_context;
> +	struct kvm_vcpu *vcpu = kvm_pmc_to_vcpu(pmc);
> +	int idx = pmc->idx;
> +
> +	kvm_pmu_overflow_set(vcpu, BIT(idx));
> +}
> +
> +/**
>   * kvm_pmu_enable_counter - enable selected PMU counter
>   * @vcpu: The vcpu pointer
>   * @val: the value guest writes to PMCNTENSET register
> @@ -258,7 +309,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  	/* The initial sample period (overflow count) of an event. */
>  	attr.sample_period = (-counter) & pmc->bitmask;
>  
> -	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
> +	event = perf_event_create_kernel_counter(&attr, -1, current,
> +						 kvm_pmu_perf_overflow, pmc);
>  	if (IS_ERR(event)) {
>  		printk_once("kvm: pmu event creation failed %ld\n",
>  			    PTR_ERR(event));
> 

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

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-15 15:33     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:33 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> the kvm_device_ops for it.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>  include/linux/kvm_host.h                      |   1 +
>  include/uapi/linux/kvm.h                      |   2 +
>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>  virt/kvm/kvm_main.c                           |   4 +
>  6 files changed, 141 insertions(+)
>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> 
> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
> new file mode 100644
> index 0000000..5121f1f
> --- /dev/null
> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> @@ -0,0 +1,16 @@
> +ARM Virtual Performance Monitor Unit (vPMU)
> +===========================================
> +
> +Device types supported:
> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> +
> +Instantiate one PMU instance for per VCPU through this API.
> +
> +Groups:
> +  KVM_DEV_ARM_PMU_GRP_IRQ
> +  Attributes:
> +    A value describing the interrupt number of PMU overflow interrupt. This
> +    interrupt should be a PPI.
> +
> +  Errors:
> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 2d4ca4b..568afa2 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
> +/* Device Control API: ARM PMU */
> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
> +
>  /* KVM_IRQ_LINE irq field index values */
>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index c923350..608dea6 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>  extern struct kvm_device_ops kvm_xics_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>  
>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>  
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 03f3618..4ba6fdd 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>  	KVM_DEV_TYPE_ARM_VGIC_V3,
>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
> +	KVM_DEV_TYPE_ARM_PMU_V3,
> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>  	KVM_DEV_TYPE_MAX,
>  };
>  
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index d113ee4..1965d0d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -19,6 +19,7 @@
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  #include <linux/perf_event.h>
> +#include <linux/uaccess.h>
>  #include <asm/kvm_emulate.h>
>  #include <kvm/arm_pmu.h>
>  #include <kvm/arm_vgic.h>
> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  
>  	pmc->perf_event = event;
>  }
> +
> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> +{
> +	return vcpu->arch.pmu.irq_num != -1;
> +}
> +
> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> +{
> +	int j;
> +	struct kvm_vcpu *vcpu;
> +
> +	kvm_for_each_vcpu(j, vcpu, kvm) {
> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +
> +		if (!is_set) {
> +			if (!kvm_arm_pmu_initialized(vcpu))
> +				return -EBUSY;

Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
anyway. Actually, why would you return an error in this case?

> +
> +			*irq = pmu->irq_num;
> +			break;
> +		}
> +
> +		if (kvm_arm_pmu_initialized(vcpu))
> +			return -EBUSY;
> +
> +		kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
> +		pmu->irq_num = *irq;
> +	}
> +
> +	return 0;
> +}
> +
> +static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
> +{
> +	int i;
> +	struct kvm_vcpu *vcpu;
> +	struct kvm *kvm = dev->kvm;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +
> +		memset(pmu, 0, sizeof(*pmu));
> +		kvm_pmu_vcpu_reset(vcpu);
> +		pmu->irq_num = -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static void kvm_arm_pmu_destroy(struct kvm_device *dev)
> +{
> +	kfree(dev);
> +}
> +
> +static int kvm_arm_pmu_set_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PMU_GRP_IRQ: {
> +		int __user *uaddr = (int __user *)(long)attr->addr;
> +		int reg;
> +
> +		if (get_user(reg, uaddr))
> +			return -EFAULT;
> +
> +		if (reg < VGIC_NR_SGIS || reg >= VGIC_NR_PRIVATE_IRQS)
> +			return -EINVAL;
> +
> +		return kvm_arm_pmu_irq_access(dev->kvm, &reg, true);
> +	}
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +static int kvm_arm_pmu_get_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	int ret;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PMU_GRP_IRQ: {
> +		int __user *uaddr = (int __user *)(long)attr->addr;
> +		int reg = -1;
> +
> +		ret = kvm_arm_pmu_irq_access(dev->kvm, &reg, false);
> +		if (ret)
> +			return ret;
> +		return put_user(reg, uaddr);
> +	}
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +static int kvm_arm_pmu_has_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PMU_GRP_IRQ:
> +		return 0;
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +struct kvm_device_ops kvm_arm_pmu_ops = {
> +	.name = "kvm-arm-pmu",
> +	.create = kvm_arm_pmu_create,
> +	.destroy = kvm_arm_pmu_destroy,
> +	.set_attr = kvm_arm_pmu_set_attr,
> +	.get_attr = kvm_arm_pmu_get_attr,
> +	.has_attr = kvm_arm_pmu_has_attr,
> +};
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 484079e..81a42cc 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -2647,6 +2647,10 @@ static struct kvm_device_ops *kvm_device_ops_table[KVM_DEV_TYPE_MAX] = {
>  #ifdef CONFIG_KVM_XICS
>  	[KVM_DEV_TYPE_XICS]		= &kvm_xics_ops,
>  #endif
> +
> +#ifdef CONFIG_KVM_ARM_PMU
> +	[KVM_DEV_TYPE_ARM_PMU_V3]	= &kvm_arm_pmu_ops,
> +#endif
>  };
>  
>  int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type)
> 

Thanks,

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

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15 15:33     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> the kvm_device_ops for it.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>  include/linux/kvm_host.h                      |   1 +
>  include/uapi/linux/kvm.h                      |   2 +
>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>  virt/kvm/kvm_main.c                           |   4 +
>  6 files changed, 141 insertions(+)
>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> 
> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
> new file mode 100644
> index 0000000..5121f1f
> --- /dev/null
> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> @@ -0,0 +1,16 @@
> +ARM Virtual Performance Monitor Unit (vPMU)
> +===========================================
> +
> +Device types supported:
> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> +
> +Instantiate one PMU instance for per VCPU through this API.
> +
> +Groups:
> +  KVM_DEV_ARM_PMU_GRP_IRQ
> +  Attributes:
> +    A value describing the interrupt number of PMU overflow interrupt. This
> +    interrupt should be a PPI.
> +
> +  Errors:
> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 2d4ca4b..568afa2 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>  
> +/* Device Control API: ARM PMU */
> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
> +
>  /* KVM_IRQ_LINE irq field index values */
>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index c923350..608dea6 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>  extern struct kvm_device_ops kvm_xics_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>  
>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>  
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 03f3618..4ba6fdd 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>  	KVM_DEV_TYPE_ARM_VGIC_V3,
>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
> +	KVM_DEV_TYPE_ARM_PMU_V3,
> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>  	KVM_DEV_TYPE_MAX,
>  };
>  
> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> index d113ee4..1965d0d 100644
> --- a/virt/kvm/arm/pmu.c
> +++ b/virt/kvm/arm/pmu.c
> @@ -19,6 +19,7 @@
>  #include <linux/kvm.h>
>  #include <linux/kvm_host.h>
>  #include <linux/perf_event.h>
> +#include <linux/uaccess.h>
>  #include <asm/kvm_emulate.h>
>  #include <kvm/arm_pmu.h>
>  #include <kvm/arm_vgic.h>
> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>  
>  	pmc->perf_event = event;
>  }
> +
> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> +{
> +	return vcpu->arch.pmu.irq_num != -1;
> +}
> +
> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> +{
> +	int j;
> +	struct kvm_vcpu *vcpu;
> +
> +	kvm_for_each_vcpu(j, vcpu, kvm) {
> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +
> +		if (!is_set) {
> +			if (!kvm_arm_pmu_initialized(vcpu))
> +				return -EBUSY;

Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
anyway. Actually, why would you return an error in this case?

> +
> +			*irq = pmu->irq_num;
> +			break;
> +		}
> +
> +		if (kvm_arm_pmu_initialized(vcpu))
> +			return -EBUSY;
> +
> +		kvm_debug("Set kvm ARM PMU irq: %d\n", *irq);
> +		pmu->irq_num = *irq;
> +	}
> +
> +	return 0;
> +}
> +
> +static int kvm_arm_pmu_create(struct kvm_device *dev, u32 type)
> +{
> +	int i;
> +	struct kvm_vcpu *vcpu;
> +	struct kvm *kvm = dev->kvm;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +
> +		memset(pmu, 0, sizeof(*pmu));
> +		kvm_pmu_vcpu_reset(vcpu);
> +		pmu->irq_num = -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static void kvm_arm_pmu_destroy(struct kvm_device *dev)
> +{
> +	kfree(dev);
> +}
> +
> +static int kvm_arm_pmu_set_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PMU_GRP_IRQ: {
> +		int __user *uaddr = (int __user *)(long)attr->addr;
> +		int reg;
> +
> +		if (get_user(reg, uaddr))
> +			return -EFAULT;
> +
> +		if (reg < VGIC_NR_SGIS || reg >= VGIC_NR_PRIVATE_IRQS)
> +			return -EINVAL;
> +
> +		return kvm_arm_pmu_irq_access(dev->kvm, &reg, true);
> +	}
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +static int kvm_arm_pmu_get_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	int ret;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PMU_GRP_IRQ: {
> +		int __user *uaddr = (int __user *)(long)attr->addr;
> +		int reg = -1;
> +
> +		ret = kvm_arm_pmu_irq_access(dev->kvm, &reg, false);
> +		if (ret)
> +			return ret;
> +		return put_user(reg, uaddr);
> +	}
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +static int kvm_arm_pmu_has_attr(struct kvm_device *dev,
> +				struct kvm_device_attr *attr)
> +{
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PMU_GRP_IRQ:
> +		return 0;
> +	}
> +
> +	return -ENXIO;
> +}
> +
> +struct kvm_device_ops kvm_arm_pmu_ops = {
> +	.name = "kvm-arm-pmu",
> +	.create = kvm_arm_pmu_create,
> +	.destroy = kvm_arm_pmu_destroy,
> +	.set_attr = kvm_arm_pmu_set_attr,
> +	.get_attr = kvm_arm_pmu_get_attr,
> +	.has_attr = kvm_arm_pmu_has_attr,
> +};
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 484079e..81a42cc 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -2647,6 +2647,10 @@ static struct kvm_device_ops *kvm_device_ops_table[KVM_DEV_TYPE_MAX] = {
>  #ifdef CONFIG_KVM_XICS
>  	[KVM_DEV_TYPE_XICS]		= &kvm_xics_ops,
>  #endif
> +
> +#ifdef CONFIG_KVM_ARM_PMU
> +	[KVM_DEV_TYPE_ARM_PMU_V3]	= &kvm_arm_pmu_ops,
> +#endif
>  };
>  
>  int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type)
> 

Thanks,

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

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

* Re: [PATCH v7 00/19] KVM: ARM64: Add guest PMU support
  2015-12-15  8:49 ` Shannon Zhao
@ 2015-12-15 15:41   ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:41 UTC (permalink / raw)
  To: Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	shannon.zhao, peter.huangpeng, hangaohuai

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> This patchset adds guest PMU support for KVM on ARM64. It takes
> trap-and-emulate approach. When guest wants to monitor one event, it
> will be trapped by KVM and KVM will call perf_event API to create a perf
> event and call relevant perf_event APIs to get the count value of event.
> 
> Use perf to test this patchset in guest. When using "perf list", it
> shows the list of the hardware events and hardware cache events perf
> supports. Then use "perf stat -e EVENT" to monitor some event. For
> example, use "perf stat -e cycles" to count cpu cycles and
> "perf stat -e cache-misses" to count cache misses.
> 
> Below are the outputs of "perf stat -r 5 sleep 5" when running in host
> and guest.
> 
> Host:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>           0.549456      task-clock (msec)         #    0.000 CPUs utilized            ( +-  5.68% )
>                  1      context-switches          #    0.002 M/sec
>                  0      cpu-migrations            #    0.000 K/sec
>                 48      page-faults               #    0.088 M/sec                    ( +-  1.40% )
>            1146243      cycles                    #    2.086 GHz                      ( +-  5.71% )
>    <not supported>      stalled-cycles-frontend
>    <not supported>      stalled-cycles-backend
>             627195      instructions              #    0.55  insns per cycle          ( +- 15.65% )
>    <not supported>      branches
>               9826      branch-misses             #   17.883 M/sec                    ( +-  1.10% )
> 
>        5.000875516 seconds time elapsed                                          ( +-  0.00% )
> 
> 
> Guest:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>           0.640712      task-clock (msec)         #    0.000 CPUs utilized            ( +-  0.41% )
>                  1      context-switches          #    0.002 M/sec
>                  0      cpu-migrations            #    0.000 K/sec
>                 50      page-faults               #    0.077 M/sec                    ( +-  1.37% )
>            1320428      cycles                    #    2.061 GHz                      ( +-  0.29% )
>    <not supported>      stalled-cycles-frontend
>    <not supported>      stalled-cycles-backend
>             642373      instructions              #    0.49  insns per cycle          ( +-  0.46% )
>    <not supported>      branches
>              10399      branch-misses             #   16.230 M/sec                    ( +-  1.57% )
> 
>        5.001181020 seconds time elapsed                                          ( +-  0.00% )
> 
> 
> Have a cycle counter read test like below in guest and host:
> 
> static void test(void)
> {
> 	unsigned long count, count1, count2;
> 	count1 = read_cycles();
> 	count++;
> 	count2 = read_cycles();
> }
> 
> Host:
> count1: 3049567104
> count2: 3049567247
> delta: 143
> 
> Guest:
> count1: 5281420890
> count2: 5281421068
> delta: 178
> 
> The gap between guest and host is very small. One reason for this I
> think is that it doesn't count the cycles in EL2 and host since we add
> exclude_hv = 1. So the cycles spent to store/restore registers which
> happens at EL2 are not included.
> 
> This patchset can be fetched from [1] and the relevant QEMU version for
> test can be fetched from [2].
> 
> The results of 'perf test' can be found from [3][4].
> The results of perf_event_tests test suite can be found from [5][6].
> 
> Also, I have tested "perf top" in two VMs and host at the same time. It
> works well.

So while things are steadily improving, there is still more things to do
(and the more I review the code, the more I find things, which worries me).

The biggest issue at the moment is the handling of accesses at EL0,
which should be forwarded to EL1 instead of ignoring the access when
denied. There is also the UNDEFINED accesses (which are pretty easy to
solve), and a couple of straightforward bugs and other nits that should
be easy to fix.

If you can fix the above and that the result looks good, I'll try to put
it into -next. But at the moment, it looks like we're not really on
track to make it into 4.5.

Thanks,

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

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

* [PATCH v7 00/19] KVM: ARM64: Add guest PMU support
@ 2015-12-15 15:41   ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 08:49, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> This patchset adds guest PMU support for KVM on ARM64. It takes
> trap-and-emulate approach. When guest wants to monitor one event, it
> will be trapped by KVM and KVM will call perf_event API to create a perf
> event and call relevant perf_event APIs to get the count value of event.
> 
> Use perf to test this patchset in guest. When using "perf list", it
> shows the list of the hardware events and hardware cache events perf
> supports. Then use "perf stat -e EVENT" to monitor some event. For
> example, use "perf stat -e cycles" to count cpu cycles and
> "perf stat -e cache-misses" to count cache misses.
> 
> Below are the outputs of "perf stat -r 5 sleep 5" when running in host
> and guest.
> 
> Host:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>           0.549456      task-clock (msec)         #    0.000 CPUs utilized            ( +-  5.68% )
>                  1      context-switches          #    0.002 M/sec
>                  0      cpu-migrations            #    0.000 K/sec
>                 48      page-faults               #    0.088 M/sec                    ( +-  1.40% )
>            1146243      cycles                    #    2.086 GHz                      ( +-  5.71% )
>    <not supported>      stalled-cycles-frontend
>    <not supported>      stalled-cycles-backend
>             627195      instructions              #    0.55  insns per cycle          ( +- 15.65% )
>    <not supported>      branches
>               9826      branch-misses             #   17.883 M/sec                    ( +-  1.10% )
> 
>        5.000875516 seconds time elapsed                                          ( +-  0.00% )
> 
> 
> Guest:
>  Performance counter stats for 'sleep 5' (5 runs):
> 
>           0.640712      task-clock (msec)         #    0.000 CPUs utilized            ( +-  0.41% )
>                  1      context-switches          #    0.002 M/sec
>                  0      cpu-migrations            #    0.000 K/sec
>                 50      page-faults               #    0.077 M/sec                    ( +-  1.37% )
>            1320428      cycles                    #    2.061 GHz                      ( +-  0.29% )
>    <not supported>      stalled-cycles-frontend
>    <not supported>      stalled-cycles-backend
>             642373      instructions              #    0.49  insns per cycle          ( +-  0.46% )
>    <not supported>      branches
>              10399      branch-misses             #   16.230 M/sec                    ( +-  1.57% )
> 
>        5.001181020 seconds time elapsed                                          ( +-  0.00% )
> 
> 
> Have a cycle counter read test like below in guest and host:
> 
> static void test(void)
> {
> 	unsigned long count, count1, count2;
> 	count1 = read_cycles();
> 	count++;
> 	count2 = read_cycles();
> }
> 
> Host:
> count1: 3049567104
> count2: 3049567247
> delta: 143
> 
> Guest:
> count1: 5281420890
> count2: 5281421068
> delta: 178
> 
> The gap between guest and host is very small. One reason for this I
> think is that it doesn't count the cycles in EL2 and host since we add
> exclude_hv = 1. So the cycles spent to store/restore registers which
> happens at EL2 are not included.
> 
> This patchset can be fetched from [1] and the relevant QEMU version for
> test can be fetched from [2].
> 
> The results of 'perf test' can be found from [3][4].
> The results of perf_event_tests test suite can be found from [5][6].
> 
> Also, I have tested "perf top" in two VMs and host at the same time. It
> works well.

So while things are steadily improving, there is still more things to do
(and the more I review the code, the more I find things, which worries me).

The biggest issue at the moment is the handling of accesses at EL0,
which should be forwarded to EL1 instead of ignoring the access when
denied. There is also the UNDEFINED accesses (which are pretty easy to
solve), and a couple of straightforward bugs and other nits that should
be easy to fix.

If you can fix the above and that the result looks good, I'll try to put
it into -next. But at the moment, it looks like we're not really on
track to make it into 4.5.

Thanks,

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

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-15 15:33     ` Marc Zyngier
@ 2015-12-15 15:50       ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15 15:50 UTC (permalink / raw)
  To: Marc Zyngier, Shannon Zhao, kvmarm, christoffer.dall
  Cc: kvm, will.deacon, linux-arm-kernel



On 2015/12/15 23:33, Marc Zyngier wrote:
> On 15/12/15 08:49, Shannon Zhao wrote:
>> >From: Shannon Zhao<shannon.zhao@linaro.org>
>> >
>> >Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>> >the kvm_device_ops for it.
>> >
>> >Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>> >---
>> >  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>> >  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>> >  include/linux/kvm_host.h                      |   1 +
>> >  include/uapi/linux/kvm.h                      |   2 +
>> >  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>> >  virt/kvm/kvm_main.c                           |   4 +
>> >  6 files changed, 141 insertions(+)
>> >  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>> >
>> >diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
>> >new file mode 100644
>> >index 0000000..5121f1f
>> >--- /dev/null
>> >+++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>> >@@ -0,0 +1,16 @@
>> >+ARM Virtual Performance Monitor Unit (vPMU)
>> >+===========================================
>> >+
>> >+Device types supported:
>> >+  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>> >+
>> >+Instantiate one PMU instance for per VCPU through this API.
>> >+
>> >+Groups:
>> >+  KVM_DEV_ARM_PMU_GRP_IRQ
>> >+  Attributes:
>> >+    A value describing the interrupt number of PMU overflow interrupt. This
>> >+    interrupt should be a PPI.
>> >+
>> >+  Errors:
>> >+    -EINVAL: Value set is out of the expected range (from 16 to 31)
>> >diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> >index 2d4ca4b..568afa2 100644
>> >--- a/arch/arm64/include/uapi/asm/kvm.h
>> >+++ b/arch/arm64/include/uapi/asm/kvm.h
>> >@@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>> >  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>> >  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>> >
>> >+/* Device Control API: ARM PMU */
>> >+#define KVM_DEV_ARM_PMU_GRP_IRQ		0
>> >+
>> >  /* KVM_IRQ_LINE irq field index values */
>> >  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>> >  #define KVM_ARM_IRQ_TYPE_MASK		0xff
>> >diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> >index c923350..608dea6 100644
>> >--- a/include/linux/kvm_host.h
>> >+++ b/include/linux/kvm_host.h
>> >@@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>> >  extern struct kvm_device_ops kvm_xics_ops;
>> >  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>> >  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>> >+extern struct kvm_device_ops kvm_arm_pmu_ops;
>> >
>> >  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>> >
>> >diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>> >index 03f3618..4ba6fdd 100644
>> >--- a/include/uapi/linux/kvm.h
>> >+++ b/include/uapi/linux/kvm.h
>> >@@ -1032,6 +1032,8 @@ enum kvm_device_type {
>> >  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>> >  	KVM_DEV_TYPE_ARM_VGIC_V3,
>> >  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
>> >+	KVM_DEV_TYPE_ARM_PMU_V3,
>> >+#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>> >  	KVM_DEV_TYPE_MAX,
>> >  };
>> >
>> >diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> >index d113ee4..1965d0d 100644
>> >--- a/virt/kvm/arm/pmu.c
>> >+++ b/virt/kvm/arm/pmu.c
>> >@@ -19,6 +19,7 @@
>> >  #include <linux/kvm.h>
>> >  #include <linux/kvm_host.h>
>> >  #include <linux/perf_event.h>
>> >+#include <linux/uaccess.h>
>> >  #include <asm/kvm_emulate.h>
>> >  #include <kvm/arm_pmu.h>
>> >  #include <kvm/arm_vgic.h>
>> >@@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>> >
>> >  	pmc->perf_event = event;
>> >  }
>> >+
>> >+static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>> >+{
>> >+	return vcpu->arch.pmu.irq_num != -1;
>> >+}
>> >+
>> >+static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>> >+{
>> >+	int j;
>> >+	struct kvm_vcpu *vcpu;
>> >+
>> >+	kvm_for_each_vcpu(j, vcpu, kvm) {
>> >+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
>> >+
>> >+		if (!is_set) {
>> >+			if (!kvm_arm_pmu_initialized(vcpu))
>> >+				return -EBUSY;
> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> anyway. Actually, why would you return an error in this case?
>
While this is a unexpected operation from user space and it's already 
initialized and working, so I think it should return an error to user 
and tell user that it's already initialized and working (this should 
mean "busy" ?).

-- 
Shannon

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15 15:50       ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15 15:50 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/15 23:33, Marc Zyngier wrote:
> On 15/12/15 08:49, Shannon Zhao wrote:
>> >From: Shannon Zhao<shannon.zhao@linaro.org>
>> >
>> >Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>> >the kvm_device_ops for it.
>> >
>> >Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>> >---
>> >  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>> >  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>> >  include/linux/kvm_host.h                      |   1 +
>> >  include/uapi/linux/kvm.h                      |   2 +
>> >  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>> >  virt/kvm/kvm_main.c                           |   4 +
>> >  6 files changed, 141 insertions(+)
>> >  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>> >
>> >diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
>> >new file mode 100644
>> >index 0000000..5121f1f
>> >--- /dev/null
>> >+++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>> >@@ -0,0 +1,16 @@
>> >+ARM Virtual Performance Monitor Unit (vPMU)
>> >+===========================================
>> >+
>> >+Device types supported:
>> >+  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>> >+
>> >+Instantiate one PMU instance for per VCPU through this API.
>> >+
>> >+Groups:
>> >+  KVM_DEV_ARM_PMU_GRP_IRQ
>> >+  Attributes:
>> >+    A value describing the interrupt number of PMU overflow interrupt. This
>> >+    interrupt should be a PPI.
>> >+
>> >+  Errors:
>> >+    -EINVAL: Value set is out of the expected range (from 16 to 31)
>> >diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> >index 2d4ca4b..568afa2 100644
>> >--- a/arch/arm64/include/uapi/asm/kvm.h
>> >+++ b/arch/arm64/include/uapi/asm/kvm.h
>> >@@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>> >  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>> >  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>> >
>> >+/* Device Control API: ARM PMU */
>> >+#define KVM_DEV_ARM_PMU_GRP_IRQ		0
>> >+
>> >  /* KVM_IRQ_LINE irq field index values */
>> >  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>> >  #define KVM_ARM_IRQ_TYPE_MASK		0xff
>> >diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>> >index c923350..608dea6 100644
>> >--- a/include/linux/kvm_host.h
>> >+++ b/include/linux/kvm_host.h
>> >@@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>> >  extern struct kvm_device_ops kvm_xics_ops;
>> >  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>> >  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>> >+extern struct kvm_device_ops kvm_arm_pmu_ops;
>> >
>> >  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>> >
>> >diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>> >index 03f3618..4ba6fdd 100644
>> >--- a/include/uapi/linux/kvm.h
>> >+++ b/include/uapi/linux/kvm.h
>> >@@ -1032,6 +1032,8 @@ enum kvm_device_type {
>> >  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>> >  	KVM_DEV_TYPE_ARM_VGIC_V3,
>> >  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
>> >+	KVM_DEV_TYPE_ARM_PMU_V3,
>> >+#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>> >  	KVM_DEV_TYPE_MAX,
>> >  };
>> >
>> >diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>> >index d113ee4..1965d0d 100644
>> >--- a/virt/kvm/arm/pmu.c
>> >+++ b/virt/kvm/arm/pmu.c
>> >@@ -19,6 +19,7 @@
>> >  #include <linux/kvm.h>
>> >  #include <linux/kvm_host.h>
>> >  #include <linux/perf_event.h>
>> >+#include <linux/uaccess.h>
>> >  #include <asm/kvm_emulate.h>
>> >  #include <kvm/arm_pmu.h>
>> >  #include <kvm/arm_vgic.h>
>> >@@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>> >
>> >  	pmc->perf_event = event;
>> >  }
>> >+
>> >+static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>> >+{
>> >+	return vcpu->arch.pmu.irq_num != -1;
>> >+}
>> >+
>> >+static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>> >+{
>> >+	int j;
>> >+	struct kvm_vcpu *vcpu;
>> >+
>> >+	kvm_for_each_vcpu(j, vcpu, kvm) {
>> >+		struct kvm_pmu *pmu = &vcpu->arch.pmu;
>> >+
>> >+		if (!is_set) {
>> >+			if (!kvm_arm_pmu_initialized(vcpu))
>> >+				return -EBUSY;
> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> anyway. Actually, why would you return an error in this case?
>
While this is a unexpected operation from user space and it's already 
initialized and working, so I think it should return an error to user 
and tell user that it's already initialized and working (this should 
mean "busy" ?).

-- 
Shannon

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

* Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
  2015-12-15 14:58     ` Marc Zyngier
@ 2015-12-15 15:59       ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15 15:59 UTC (permalink / raw)
  To: Marc Zyngier, Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	peter.huangpeng, hangaohuai



On 2015/12/15 22:58, Marc Zyngier wrote:
> On 15/12/15 08:49, Shannon Zhao wrote:
>> >From: Shannon Zhao<shannon.zhao@linaro.org>
>> >
>> >The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
>> >
>> >PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
>> >accessed from EL0. Add some check helpers to handle the access from EL0.
>> >
>> >Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>> >---
>> >  arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
>> >  1 file changed, 119 insertions(+), 5 deletions(-)
>> >
>> >diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> >index b2ccc25..bad3dfd 100644
>> >--- a/arch/arm64/kvm/sys_regs.c
>> >+++ b/arch/arm64/kvm/sys_regs.c
>> >@@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>> >  	vcpu_sys_reg(vcpu, r->reg) = val;
>> >  }
>> >
>> >+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
>> >+}
>> >+
>> >+static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
>> >+}
>> >+
>> >+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
>> >+}
>> >+
>> >+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
>> >+}
> Please add #defines for the PMUSERNR_EL0 bits.
>
>> >+
>> >  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>> >  			const struct sys_reg_desc *r)
>> >  {
>> >  	u64 val;
>> >+	bool unaccessible = pmu_access_el0_disabled(vcpu);
>> >
>> >  	if (p->is_write) {
>> >+		if (unaccessible)
>> >+			return ignore_write(vcpu, p);
>> >+
> This is not how this is supposed to work. If EL0 is denied access to the
> PMU, you must inject an exception into EL1 for it to handle the fault.
> The code should reflect the flow described at D5.11.2 in the ARM ARM.
>
Does it need to add a helper to inject an exception into EL1 or is there 
a existing one?

Thanks,
-- 
Shannon

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

* [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
@ 2015-12-15 15:59       ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-15 15:59 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/15 22:58, Marc Zyngier wrote:
> On 15/12/15 08:49, Shannon Zhao wrote:
>> >From: Shannon Zhao<shannon.zhao@linaro.org>
>> >
>> >The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
>> >
>> >PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
>> >accessed from EL0. Add some check helpers to handle the access from EL0.
>> >
>> >Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>> >---
>> >  arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
>> >  1 file changed, 119 insertions(+), 5 deletions(-)
>> >
>> >diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> >index b2ccc25..bad3dfd 100644
>> >--- a/arch/arm64/kvm/sys_regs.c
>> >+++ b/arch/arm64/kvm/sys_regs.c
>> >@@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>> >  	vcpu_sys_reg(vcpu, r->reg) = val;
>> >  }
>> >
>> >+static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
>> >+}
>> >+
>> >+static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
>> >+}
>> >+
>> >+static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
>> >+}
>> >+
>> >+static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
>> >+{
>> >+	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>> >+
>> >+	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
>> >+}
> Please add #defines for the PMUSERNR_EL0 bits.
>
>> >+
>> >  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>> >  			const struct sys_reg_desc *r)
>> >  {
>> >  	u64 val;
>> >+	bool unaccessible = pmu_access_el0_disabled(vcpu);
>> >
>> >  	if (p->is_write) {
>> >+		if (unaccessible)
>> >+			return ignore_write(vcpu, p);
>> >+
> This is not how this is supposed to work. If EL0 is denied access to the
> PMU, you must inject an exception into EL1 for it to handle the fault.
> The code should reflect the flow described at D5.11.2 in the ARM ARM.
>
Does it need to add a helper to inject an exception into EL1 or is there 
a existing one?

Thanks,
-- 
Shannon

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-15 15:50       ` Shannon Zhao
@ 2015-12-15 15:59         ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:59 UTC (permalink / raw)
  To: Shannon Zhao, Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	peter.huangpeng, hangaohuai

On 15/12/15 15:50, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 23:33, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
>>>> From: Shannon Zhao<shannon.zhao@linaro.org>
>>>>
>>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>>>> the kvm_device_ops for it.
>>>>
>>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>>>> ---
>>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>>>>  include/linux/kvm_host.h                      |   1 +
>>>>  include/uapi/linux/kvm.h                      |   2 +
>>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>>>>  virt/kvm/kvm_main.c                           |   4 +
>>>>  6 files changed, 141 insertions(+)
>>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>
>>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>> new file mode 100644
>>>> index 0000000..5121f1f
>>>> --- /dev/null
>>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>> @@ -0,0 +1,16 @@
>>>> +ARM Virtual Performance Monitor Unit (vPMU)
>>>> +===========================================
>>>> +
>>>> +Device types supported:
>>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>> +
>>>> +Instantiate one PMU instance for per VCPU through this API.
>>>> +
>>>> +Groups:
>>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
>>>> +  Attributes:
>>>> +    A value describing the interrupt number of PMU overflow interrupt. This
>>>> +    interrupt should be a PPI.
>>>> +
>>>> +  Errors:
>>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
>>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>>> index 2d4ca4b..568afa2 100644
>>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>>>>
>>>> +/* Device Control API: ARM PMU */
>>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
>>>> +
>>>>  /* KVM_IRQ_LINE irq field index values */
>>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
>>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>>>> index c923350..608dea6 100644
>>>> --- a/include/linux/kvm_host.h
>>>> +++ b/include/linux/kvm_host.h
>>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>>>>  extern struct kvm_device_ops kvm_xics_ops;
>>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>>>>
>>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>>>>
>>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>> index 03f3618..4ba6fdd 100644
>>>> --- a/include/uapi/linux/kvm.h
>>>> +++ b/include/uapi/linux/kvm.h
>>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
>>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
>>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
>>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>>>>  	KVM_DEV_TYPE_MAX,
>>>>  };
>>>>
>>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>>>> index d113ee4..1965d0d 100644
>>>> --- a/virt/kvm/arm/pmu.c
>>>> +++ b/virt/kvm/arm/pmu.c
>>>> @@ -19,6 +19,7 @@
>>>>  #include <linux/kvm.h>
>>>>  #include <linux/kvm_host.h>
>>>>  #include <linux/perf_event.h>
>>>> +#include <linux/uaccess.h>
>>>>  #include <asm/kvm_emulate.h>
>>>>  #include <kvm/arm_pmu.h>
>>>>  #include <kvm/arm_vgic.h>
>>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>>>>
>>>>  	pmc->perf_event = event;
>>>>  }
>>>> +
>>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	return vcpu->arch.pmu.irq_num != -1;
>>>> +}
>>>> +
>>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>>>> +{
>>>> +	int j;
>>>> +	struct kvm_vcpu *vcpu;
>>>> +
>>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
>>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
>>>> +
>>>> +		if (!is_set) {
>>>> +			if (!kvm_arm_pmu_initialized(vcpu))
>>>> +				return -EBUSY;
>> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
>> anyway. Actually, why would you return an error in this case?
>>
> While this is a unexpected operation from user space and it's already 
> initialized and working, so I think it should return an error to user 
> and tell user that it's already initialized and working (this should 
> mean "busy" ?).

But in this case, you're returning an error if it is *not* initialized.
I understand that in that case you cannot return an interrupt number (-1
would be weird), but returning -EBUSY feels even more weird.

I'd settle for -ENOXIO, or something similar. Anyone having a better idea?

Thanks,

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

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15 15:59         ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 15:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 15:50, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 23:33, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
>>>> From: Shannon Zhao<shannon.zhao@linaro.org>
>>>>
>>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>>>> the kvm_device_ops for it.
>>>>
>>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>>>> ---
>>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>>>>  include/linux/kvm_host.h                      |   1 +
>>>>  include/uapi/linux/kvm.h                      |   2 +
>>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>>>>  virt/kvm/kvm_main.c                           |   4 +
>>>>  6 files changed, 141 insertions(+)
>>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>
>>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>> new file mode 100644
>>>> index 0000000..5121f1f
>>>> --- /dev/null
>>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>> @@ -0,0 +1,16 @@
>>>> +ARM Virtual Performance Monitor Unit (vPMU)
>>>> +===========================================
>>>> +
>>>> +Device types supported:
>>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>> +
>>>> +Instantiate one PMU instance for per VCPU through this API.
>>>> +
>>>> +Groups:
>>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
>>>> +  Attributes:
>>>> +    A value describing the interrupt number of PMU overflow interrupt. This
>>>> +    interrupt should be a PPI.
>>>> +
>>>> +  Errors:
>>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
>>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>>> index 2d4ca4b..568afa2 100644
>>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>>>>
>>>> +/* Device Control API: ARM PMU */
>>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
>>>> +
>>>>  /* KVM_IRQ_LINE irq field index values */
>>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
>>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>>>> index c923350..608dea6 100644
>>>> --- a/include/linux/kvm_host.h
>>>> +++ b/include/linux/kvm_host.h
>>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>>>>  extern struct kvm_device_ops kvm_xics_ops;
>>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>>>>
>>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>>>>
>>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>> index 03f3618..4ba6fdd 100644
>>>> --- a/include/uapi/linux/kvm.h
>>>> +++ b/include/uapi/linux/kvm.h
>>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
>>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
>>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
>>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>>>>  	KVM_DEV_TYPE_MAX,
>>>>  };
>>>>
>>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>>>> index d113ee4..1965d0d 100644
>>>> --- a/virt/kvm/arm/pmu.c
>>>> +++ b/virt/kvm/arm/pmu.c
>>>> @@ -19,6 +19,7 @@
>>>>  #include <linux/kvm.h>
>>>>  #include <linux/kvm_host.h>
>>>>  #include <linux/perf_event.h>
>>>> +#include <linux/uaccess.h>
>>>>  #include <asm/kvm_emulate.h>
>>>>  #include <kvm/arm_pmu.h>
>>>>  #include <kvm/arm_vgic.h>
>>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>>>>
>>>>  	pmc->perf_event = event;
>>>>  }
>>>> +
>>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	return vcpu->arch.pmu.irq_num != -1;
>>>> +}
>>>> +
>>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>>>> +{
>>>> +	int j;
>>>> +	struct kvm_vcpu *vcpu;
>>>> +
>>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
>>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
>>>> +
>>>> +		if (!is_set) {
>>>> +			if (!kvm_arm_pmu_initialized(vcpu))
>>>> +				return -EBUSY;
>> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
>> anyway. Actually, why would you return an error in this case?
>>
> While this is a unexpected operation from user space and it's already 
> initialized and working, so I think it should return an error to user 
> and tell user that it's already initialized and working (this should 
> mean "busy" ?).

But in this case, you're returning an error if it is *not* initialized.
I understand that in that case you cannot return an interrupt number (-1
would be weird), but returning -EBUSY feels even more weird.

I'd settle for -ENOXIO, or something similar. Anyone having a better idea?

Thanks,

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

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

* Re: [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
  2015-12-15 15:59       ` Shannon Zhao
@ 2015-12-15 16:02         ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 16:02 UTC (permalink / raw)
  To: Shannon Zhao, Shannon Zhao, kvmarm, christoffer.dall
  Cc: linux-arm-kernel, kvm, will.deacon, alex.bennee, wei, cov,
	peter.huangpeng, hangaohuai

On 15/12/15 15:59, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 22:58, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
>>>> From: Shannon Zhao<shannon.zhao@linaro.org>
>>>>
>>>> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
>>>>
>>>> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
>>>> accessed from EL0. Add some check helpers to handle the access from EL0.
>>>>
>>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>>>> ---
>>>>  arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
>>>>  1 file changed, 119 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>>>> index b2ccc25..bad3dfd 100644
>>>> --- a/arch/arm64/kvm/sys_regs.c
>>>> +++ b/arch/arm64/kvm/sys_regs.c
>>>> @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>>>>  	vcpu_sys_reg(vcpu, r->reg) = val;
>>>>  }
>>>>
>>>> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
>>>> +}
>> Please add #defines for the PMUSERNR_EL0 bits.
>>
>>>> +
>>>>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>>>>  			const struct sys_reg_desc *r)
>>>>  {
>>>>  	u64 val;
>>>> +	bool unaccessible = pmu_access_el0_disabled(vcpu);
>>>>
>>>>  	if (p->is_write) {
>>>> +		if (unaccessible)
>>>> +			return ignore_write(vcpu, p);
>>>> +
>> This is not how this is supposed to work. If EL0 is denied access to the
>> PMU, you must inject an exception into EL1 for it to handle the fault.
>> The code should reflect the flow described at D5.11.2 in the ARM ARM.
>>
> Does it need to add a helper to inject an exception into EL1 or is there 
> a existing one?

You can use some of the stuff in inject_fault.c as a starting point.

Thanks,

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

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

* [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register
@ 2015-12-15 16:02         ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-15 16:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 15/12/15 15:59, Shannon Zhao wrote:
> 
> 
> On 2015/12/15 22:58, Marc Zyngier wrote:
>> On 15/12/15 08:49, Shannon Zhao wrote:
>>>> From: Shannon Zhao<shannon.zhao@linaro.org>
>>>>
>>>> The reset value of PMUSERENR_EL0 is UNKNOWN, use reset_unknown.
>>>>
>>>> PMUSERENR_EL0 holds some bits which decide whether PMU registers can be
>>>> accessed from EL0. Add some check helpers to handle the access from EL0.
>>>>
>>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>>>> ---
>>>>  arch/arm64/kvm/sys_regs.c | 124 ++++++++++++++++++++++++++++++++++++++++++++--
>>>>  1 file changed, 119 insertions(+), 5 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>>>> index b2ccc25..bad3dfd 100644
>>>> --- a/arch/arm64/kvm/sys_regs.c
>>>> +++ b/arch/arm64/kvm/sys_regs.c
>>>> @@ -452,12 +452,44 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>>>>  	vcpu_sys_reg(vcpu, r->reg) = val;
>>>>  }
>>>>
>>>> +static inline bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x1) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x3) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x5) || vcpu_mode_priv(vcpu));
>>>> +}
>>>> +
>>>> +static inline bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u64 reg = vcpu_sys_reg(vcpu, PMUSERENR_EL0);
>>>> +
>>>> +	return !((reg & 0x9) || vcpu_mode_priv(vcpu));
>>>> +}
>> Please add #defines for the PMUSERNR_EL0 bits.
>>
>>>> +
>>>>  static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>>>>  			const struct sys_reg_desc *r)
>>>>  {
>>>>  	u64 val;
>>>> +	bool unaccessible = pmu_access_el0_disabled(vcpu);
>>>>
>>>>  	if (p->is_write) {
>>>> +		if (unaccessible)
>>>> +			return ignore_write(vcpu, p);
>>>> +
>> This is not how this is supposed to work. If EL0 is denied access to the
>> PMU, you must inject an exception into EL1 for it to handle the fault.
>> The code should reflect the flow described at D5.11.2 in the ARM ARM.
>>
> Does it need to add a helper to inject an exception into EL1 or is there 
> a existing one?

You can use some of the stuff in inject_fault.c as a starting point.

Thanks,

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

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-15 15:59         ` Marc Zyngier
  (?)
@ 2015-12-15 17:50           ` Andrew Jones
  -1 siblings, 0 replies; 135+ messages in thread
From: Andrew Jones @ 2015-12-15 17:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: linux-arm-kernel, kvm, will.deacon, qemu-devel, Shannon Zhao, kvmarm

On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
> On 15/12/15 15:50, Shannon Zhao wrote:
> > 
> > 
> > On 2015/12/15 23:33, Marc Zyngier wrote:
> >> On 15/12/15 08:49, Shannon Zhao wrote:
> >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
> >>>>
> >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> >>>> the kvm_device_ops for it.
> >>>>
> >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
> >>>> ---
> >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
> >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
> >>>>  include/linux/kvm_host.h                      |   1 +
> >>>>  include/uapi/linux/kvm.h                      |   2 +
> >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
> >>>>  virt/kvm/kvm_main.c                           |   4 +
> >>>>  6 files changed, 141 insertions(+)
> >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>>
> >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> new file mode 100644
> >>>> index 0000000..5121f1f
> >>>> --- /dev/null
> >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> @@ -0,0 +1,16 @@
> >>>> +ARM Virtual Performance Monitor Unit (vPMU)
> >>>> +===========================================
> >>>> +
> >>>> +Device types supported:
> >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>>> +
> >>>> +Instantiate one PMU instance for per VCPU through this API.
> >>>> +
> >>>> +Groups:
> >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
> >>>> +  Attributes:
> >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
> >>>> +    interrupt should be a PPI.
> >>>> +
> >>>> +  Errors:
> >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
> >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> >>>> index 2d4ca4b..568afa2 100644
> >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
> >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
> >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
> >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
> >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
> >>>>
> >>>> +/* Device Control API: ARM PMU */
> >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
> >>>> +
> >>>>  /* KVM_IRQ_LINE irq field index values */
> >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
> >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
> >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> >>>> index c923350..608dea6 100644
> >>>> --- a/include/linux/kvm_host.h
> >>>> +++ b/include/linux/kvm_host.h
> >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
> >>>>  extern struct kvm_device_ops kvm_xics_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
> >>>>
> >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
> >>>>
> >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >>>> index 03f3618..4ba6fdd 100644
> >>>> --- a/include/uapi/linux/kvm.h
> >>>> +++ b/include/uapi/linux/kvm.h
> >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
> >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
> >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
> >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
> >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
> >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
> >>>>  	KVM_DEV_TYPE_MAX,
> >>>>  };
> >>>>
> >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> >>>> index d113ee4..1965d0d 100644
> >>>> --- a/virt/kvm/arm/pmu.c
> >>>> +++ b/virt/kvm/arm/pmu.c
> >>>> @@ -19,6 +19,7 @@
> >>>>  #include <linux/kvm.h>
> >>>>  #include <linux/kvm_host.h>
> >>>>  #include <linux/perf_event.h>
> >>>> +#include <linux/uaccess.h>
> >>>>  #include <asm/kvm_emulate.h>
> >>>>  #include <kvm/arm_pmu.h>
> >>>>  #include <kvm/arm_vgic.h>
> >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> >>>>
> >>>>  	pmc->perf_event = event;
> >>>>  }
> >>>> +
> >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> >>>> +{
> >>>> +	return vcpu->arch.pmu.irq_num != -1;
> >>>> +}
> >>>> +
> >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> >>>> +{
> >>>> +	int j;
> >>>> +	struct kvm_vcpu *vcpu;
> >>>> +
> >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
> >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> >>>> +
> >>>> +		if (!is_set) {
> >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
> >>>> +				return -EBUSY;
> >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> >> anyway. Actually, why would you return an error in this case?
> >>
> > While this is a unexpected operation from user space and it's already 
> > initialized and working, so I think it should return an error to user 
> > and tell user that it's already initialized and working (this should 
> > mean "busy" ?).
> 
> But in this case, you're returning an error if it is *not* initialized.
> I understand that in that case you cannot return an interrupt number (-1
> would be weird), but returning -EBUSY feels even more weird.
> 
> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?

Added qemu-devel (Peter). I think for the most part QEMU just stringifies
errnos and outputs them. So, in the absence of a kernel message, having
more unique errnos does help zero-in on a problem. However EINVAL plus a
kernel message is probably even better, and it doesn't start with people
trying to understand why a particular errno (which makes about as much
sense as EINVAL, but seems to be attempting to provide something more...)
was used.

Thanks,
drew

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

* Re: [Qemu-devel] [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15 17:50           ` Andrew Jones
  0 siblings, 0 replies; 135+ messages in thread
From: Andrew Jones @ 2015-12-15 17:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: linux-arm-kernel, peter.maydell, kvm, will.deacon, qemu-devel,
	Shannon Zhao, Shannon Zhao, kvmarm, christoffer.dall

On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
> On 15/12/15 15:50, Shannon Zhao wrote:
> > 
> > 
> > On 2015/12/15 23:33, Marc Zyngier wrote:
> >> On 15/12/15 08:49, Shannon Zhao wrote:
> >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
> >>>>
> >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> >>>> the kvm_device_ops for it.
> >>>>
> >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
> >>>> ---
> >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
> >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
> >>>>  include/linux/kvm_host.h                      |   1 +
> >>>>  include/uapi/linux/kvm.h                      |   2 +
> >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
> >>>>  virt/kvm/kvm_main.c                           |   4 +
> >>>>  6 files changed, 141 insertions(+)
> >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>>
> >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> new file mode 100644
> >>>> index 0000000..5121f1f
> >>>> --- /dev/null
> >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> @@ -0,0 +1,16 @@
> >>>> +ARM Virtual Performance Monitor Unit (vPMU)
> >>>> +===========================================
> >>>> +
> >>>> +Device types supported:
> >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>>> +
> >>>> +Instantiate one PMU instance for per VCPU through this API.
> >>>> +
> >>>> +Groups:
> >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
> >>>> +  Attributes:
> >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
> >>>> +    interrupt should be a PPI.
> >>>> +
> >>>> +  Errors:
> >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
> >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> >>>> index 2d4ca4b..568afa2 100644
> >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
> >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
> >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
> >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
> >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
> >>>>
> >>>> +/* Device Control API: ARM PMU */
> >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
> >>>> +
> >>>>  /* KVM_IRQ_LINE irq field index values */
> >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
> >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
> >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> >>>> index c923350..608dea6 100644
> >>>> --- a/include/linux/kvm_host.h
> >>>> +++ b/include/linux/kvm_host.h
> >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
> >>>>  extern struct kvm_device_ops kvm_xics_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
> >>>>
> >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
> >>>>
> >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >>>> index 03f3618..4ba6fdd 100644
> >>>> --- a/include/uapi/linux/kvm.h
> >>>> +++ b/include/uapi/linux/kvm.h
> >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
> >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
> >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
> >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
> >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
> >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
> >>>>  	KVM_DEV_TYPE_MAX,
> >>>>  };
> >>>>
> >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> >>>> index d113ee4..1965d0d 100644
> >>>> --- a/virt/kvm/arm/pmu.c
> >>>> +++ b/virt/kvm/arm/pmu.c
> >>>> @@ -19,6 +19,7 @@
> >>>>  #include <linux/kvm.h>
> >>>>  #include <linux/kvm_host.h>
> >>>>  #include <linux/perf_event.h>
> >>>> +#include <linux/uaccess.h>
> >>>>  #include <asm/kvm_emulate.h>
> >>>>  #include <kvm/arm_pmu.h>
> >>>>  #include <kvm/arm_vgic.h>
> >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> >>>>
> >>>>  	pmc->perf_event = event;
> >>>>  }
> >>>> +
> >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> >>>> +{
> >>>> +	return vcpu->arch.pmu.irq_num != -1;
> >>>> +}
> >>>> +
> >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> >>>> +{
> >>>> +	int j;
> >>>> +	struct kvm_vcpu *vcpu;
> >>>> +
> >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
> >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> >>>> +
> >>>> +		if (!is_set) {
> >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
> >>>> +				return -EBUSY;
> >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> >> anyway. Actually, why would you return an error in this case?
> >>
> > While this is a unexpected operation from user space and it's already 
> > initialized and working, so I think it should return an error to user 
> > and tell user that it's already initialized and working (this should 
> > mean "busy" ?).
> 
> But in this case, you're returning an error if it is *not* initialized.
> I understand that in that case you cannot return an interrupt number (-1
> would be weird), but returning -EBUSY feels even more weird.
> 
> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?

Added qemu-devel (Peter). I think for the most part QEMU just stringifies
errnos and outputs them. So, in the absence of a kernel message, having
more unique errnos does help zero-in on a problem. However EINVAL plus a
kernel message is probably even better, and it doesn't start with people
trying to understand why a particular errno (which makes about as much
sense as EINVAL, but seems to be attempting to provide something more...)
was used.

Thanks,
drew

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15 17:50           ` Andrew Jones
  0 siblings, 0 replies; 135+ messages in thread
From: Andrew Jones @ 2015-12-15 17:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
> On 15/12/15 15:50, Shannon Zhao wrote:
> > 
> > 
> > On 2015/12/15 23:33, Marc Zyngier wrote:
> >> On 15/12/15 08:49, Shannon Zhao wrote:
> >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
> >>>>
> >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> >>>> the kvm_device_ops for it.
> >>>>
> >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
> >>>> ---
> >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
> >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
> >>>>  include/linux/kvm_host.h                      |   1 +
> >>>>  include/uapi/linux/kvm.h                      |   2 +
> >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
> >>>>  virt/kvm/kvm_main.c                           |   4 +
> >>>>  6 files changed, 141 insertions(+)
> >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>>
> >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> new file mode 100644
> >>>> index 0000000..5121f1f
> >>>> --- /dev/null
> >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> @@ -0,0 +1,16 @@
> >>>> +ARM Virtual Performance Monitor Unit (vPMU)
> >>>> +===========================================
> >>>> +
> >>>> +Device types supported:
> >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>>> +
> >>>> +Instantiate one PMU instance for per VCPU through this API.
> >>>> +
> >>>> +Groups:
> >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
> >>>> +  Attributes:
> >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
> >>>> +    interrupt should be a PPI.
> >>>> +
> >>>> +  Errors:
> >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
> >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> >>>> index 2d4ca4b..568afa2 100644
> >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
> >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
> >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
> >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
> >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
> >>>>
> >>>> +/* Device Control API: ARM PMU */
> >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
> >>>> +
> >>>>  /* KVM_IRQ_LINE irq field index values */
> >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
> >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
> >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> >>>> index c923350..608dea6 100644
> >>>> --- a/include/linux/kvm_host.h
> >>>> +++ b/include/linux/kvm_host.h
> >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
> >>>>  extern struct kvm_device_ops kvm_xics_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
> >>>>
> >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
> >>>>
> >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >>>> index 03f3618..4ba6fdd 100644
> >>>> --- a/include/uapi/linux/kvm.h
> >>>> +++ b/include/uapi/linux/kvm.h
> >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
> >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
> >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
> >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
> >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
> >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
> >>>>  	KVM_DEV_TYPE_MAX,
> >>>>  };
> >>>>
> >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> >>>> index d113ee4..1965d0d 100644
> >>>> --- a/virt/kvm/arm/pmu.c
> >>>> +++ b/virt/kvm/arm/pmu.c
> >>>> @@ -19,6 +19,7 @@
> >>>>  #include <linux/kvm.h>
> >>>>  #include <linux/kvm_host.h>
> >>>>  #include <linux/perf_event.h>
> >>>> +#include <linux/uaccess.h>
> >>>>  #include <asm/kvm_emulate.h>
> >>>>  #include <kvm/arm_pmu.h>
> >>>>  #include <kvm/arm_vgic.h>
> >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> >>>>
> >>>>  	pmc->perf_event = event;
> >>>>  }
> >>>> +
> >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> >>>> +{
> >>>> +	return vcpu->arch.pmu.irq_num != -1;
> >>>> +}
> >>>> +
> >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> >>>> +{
> >>>> +	int j;
> >>>> +	struct kvm_vcpu *vcpu;
> >>>> +
> >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
> >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> >>>> +
> >>>> +		if (!is_set) {
> >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
> >>>> +				return -EBUSY;
> >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> >> anyway. Actually, why would you return an error in this case?
> >>
> > While this is a unexpected operation from user space and it's already 
> > initialized and working, so I think it should return an error to user 
> > and tell user that it's already initialized and working (this should 
> > mean "busy" ?).
> 
> But in this case, you're returning an error if it is *not* initialized.
> I understand that in that case you cannot return an interrupt number (-1
> would be weird), but returning -EBUSY feels even more weird.
> 
> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?

Added qemu-devel (Peter). I think for the most part QEMU just stringifies
errnos and outputs them. So, in the absence of a kernel message, having
more unique errnos does help zero-in on a problem. However EINVAL plus a
kernel message is probably even better, and it doesn't start with people
trying to understand why a particular errno (which makes about as much
sense as EINVAL, but seems to be attempting to provide something more...)
was used.

Thanks,
drew

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-15 15:59         ` Marc Zyngier
@ 2015-12-15 20:47           ` Christoffer Dall
  -1 siblings, 0 replies; 135+ messages in thread
From: Christoffer Dall @ 2015-12-15 20:47 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Shannon Zhao, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai

On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
> On 15/12/15 15:50, Shannon Zhao wrote:
> > 
> > 
> > On 2015/12/15 23:33, Marc Zyngier wrote:
> >> On 15/12/15 08:49, Shannon Zhao wrote:
> >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
> >>>>
> >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> >>>> the kvm_device_ops for it.
> >>>>
> >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
> >>>> ---
> >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
> >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
> >>>>  include/linux/kvm_host.h                      |   1 +
> >>>>  include/uapi/linux/kvm.h                      |   2 +
> >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
> >>>>  virt/kvm/kvm_main.c                           |   4 +
> >>>>  6 files changed, 141 insertions(+)
> >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>>
> >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> new file mode 100644
> >>>> index 0000000..5121f1f
> >>>> --- /dev/null
> >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> @@ -0,0 +1,16 @@
> >>>> +ARM Virtual Performance Monitor Unit (vPMU)
> >>>> +===========================================
> >>>> +
> >>>> +Device types supported:
> >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>>> +
> >>>> +Instantiate one PMU instance for per VCPU through this API.
> >>>> +
> >>>> +Groups:
> >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
> >>>> +  Attributes:
> >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
> >>>> +    interrupt should be a PPI.
> >>>> +
> >>>> +  Errors:
> >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
> >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> >>>> index 2d4ca4b..568afa2 100644
> >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
> >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
> >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
> >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
> >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
> >>>>
> >>>> +/* Device Control API: ARM PMU */
> >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
> >>>> +
> >>>>  /* KVM_IRQ_LINE irq field index values */
> >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
> >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
> >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> >>>> index c923350..608dea6 100644
> >>>> --- a/include/linux/kvm_host.h
> >>>> +++ b/include/linux/kvm_host.h
> >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
> >>>>  extern struct kvm_device_ops kvm_xics_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
> >>>>
> >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
> >>>>
> >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >>>> index 03f3618..4ba6fdd 100644
> >>>> --- a/include/uapi/linux/kvm.h
> >>>> +++ b/include/uapi/linux/kvm.h
> >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
> >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
> >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
> >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
> >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
> >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
> >>>>  	KVM_DEV_TYPE_MAX,
> >>>>  };
> >>>>
> >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> >>>> index d113ee4..1965d0d 100644
> >>>> --- a/virt/kvm/arm/pmu.c
> >>>> +++ b/virt/kvm/arm/pmu.c
> >>>> @@ -19,6 +19,7 @@
> >>>>  #include <linux/kvm.h>
> >>>>  #include <linux/kvm_host.h>
> >>>>  #include <linux/perf_event.h>
> >>>> +#include <linux/uaccess.h>
> >>>>  #include <asm/kvm_emulate.h>
> >>>>  #include <kvm/arm_pmu.h>
> >>>>  #include <kvm/arm_vgic.h>
> >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> >>>>
> >>>>  	pmc->perf_event = event;
> >>>>  }
> >>>> +
> >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> >>>> +{
> >>>> +	return vcpu->arch.pmu.irq_num != -1;
> >>>> +}
> >>>> +
> >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> >>>> +{
> >>>> +	int j;
> >>>> +	struct kvm_vcpu *vcpu;
> >>>> +
> >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
> >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> >>>> +
> >>>> +		if (!is_set) {
> >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
> >>>> +				return -EBUSY;
> >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> >> anyway. Actually, why would you return an error in this case?
> >>
> > While this is a unexpected operation from user space and it's already 
> > initialized and working, so I think it should return an error to user 
> > and tell user that it's already initialized and working (this should 
> > mean "busy" ?).
> 
> But in this case, you're returning an error if it is *not* initialized.
> I understand that in that case you cannot return an interrupt number (-1
> would be weird), but returning -EBUSY feels even more weird.
> 
> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> 
ENXIO or ENODEV would be my choice too, and add that to the
Documentation clearly describing when this error code is used.

By the way, why do you loop over all VCPUS to set the same value when
you can't do anything per VCPU anyway?  It seems to me it's either a
per-VM property (that you can store on the VM data structure) or it's a
true per-VCPU property?

-Christoffer

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-15 20:47           ` Christoffer Dall
  0 siblings, 0 replies; 135+ messages in thread
From: Christoffer Dall @ 2015-12-15 20:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
> On 15/12/15 15:50, Shannon Zhao wrote:
> > 
> > 
> > On 2015/12/15 23:33, Marc Zyngier wrote:
> >> On 15/12/15 08:49, Shannon Zhao wrote:
> >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
> >>>>
> >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
> >>>> the kvm_device_ops for it.
> >>>>
> >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
> >>>> ---
> >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
> >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
> >>>>  include/linux/kvm_host.h                      |   1 +
> >>>>  include/uapi/linux/kvm.h                      |   2 +
> >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
> >>>>  virt/kvm/kvm_main.c                           |   4 +
> >>>>  6 files changed, 141 insertions(+)
> >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>>
> >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> new file mode 100644
> >>>> index 0000000..5121f1f
> >>>> --- /dev/null
> >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
> >>>> @@ -0,0 +1,16 @@
> >>>> +ARM Virtual Performance Monitor Unit (vPMU)
> >>>> +===========================================
> >>>> +
> >>>> +Device types supported:
> >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>>> +
> >>>> +Instantiate one PMU instance for per VCPU through this API.
> >>>> +
> >>>> +Groups:
> >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
> >>>> +  Attributes:
> >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
> >>>> +    interrupt should be a PPI.
> >>>> +
> >>>> +  Errors:
> >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
> >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> >>>> index 2d4ca4b..568afa2 100644
> >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
> >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
> >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
> >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
> >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
> >>>>
> >>>> +/* Device Control API: ARM PMU */
> >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
> >>>> +
> >>>>  /* KVM_IRQ_LINE irq field index values */
> >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
> >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
> >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> >>>> index c923350..608dea6 100644
> >>>> --- a/include/linux/kvm_host.h
> >>>> +++ b/include/linux/kvm_host.h
> >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
> >>>>  extern struct kvm_device_ops kvm_xics_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
> >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
> >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
> >>>>
> >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
> >>>>
> >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> >>>> index 03f3618..4ba6fdd 100644
> >>>> --- a/include/uapi/linux/kvm.h
> >>>> +++ b/include/uapi/linux/kvm.h
> >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
> >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
> >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
> >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
> >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
> >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
> >>>>  	KVM_DEV_TYPE_MAX,
> >>>>  };
> >>>>
> >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
> >>>> index d113ee4..1965d0d 100644
> >>>> --- a/virt/kvm/arm/pmu.c
> >>>> +++ b/virt/kvm/arm/pmu.c
> >>>> @@ -19,6 +19,7 @@
> >>>>  #include <linux/kvm.h>
> >>>>  #include <linux/kvm_host.h>
> >>>>  #include <linux/perf_event.h>
> >>>> +#include <linux/uaccess.h>
> >>>>  #include <asm/kvm_emulate.h>
> >>>>  #include <kvm/arm_pmu.h>
> >>>>  #include <kvm/arm_vgic.h>
> >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> >>>>
> >>>>  	pmc->perf_event = event;
> >>>>  }
> >>>> +
> >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
> >>>> +{
> >>>> +	return vcpu->arch.pmu.irq_num != -1;
> >>>> +}
> >>>> +
> >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
> >>>> +{
> >>>> +	int j;
> >>>> +	struct kvm_vcpu *vcpu;
> >>>> +
> >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
> >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
> >>>> +
> >>>> +		if (!is_set) {
> >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
> >>>> +				return -EBUSY;
> >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
> >> anyway. Actually, why would you return an error in this case?
> >>
> > While this is a unexpected operation from user space and it's already 
> > initialized and working, so I think it should return an error to user 
> > and tell user that it's already initialized and working (this should 
> > mean "busy" ?).
> 
> But in this case, you're returning an error if it is *not* initialized.
> I understand that in that case you cannot return an interrupt number (-1
> would be weird), but returning -EBUSY feels even more weird.
> 
> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> 
ENXIO or ENODEV would be my choice too, and add that to the
Documentation clearly describing when this error code is used.

By the way, why do you loop over all VCPUS to set the same value when
you can't do anything per VCPU anyway?  It seems to me it's either a
per-VM property (that you can store on the VM data structure) or it's a
true per-VCPU property?

-Christoffer

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-15 20:47           ` Christoffer Dall
  (?)
@ 2015-12-16  7:31             ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  7:31 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/16 4:47, Christoffer Dall wrote:
> On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
>> > On 15/12/15 15:50, Shannon Zhao wrote:
>>> > > 
>>> > > 
>>> > > On 2015/12/15 23:33, Marc Zyngier wrote:
>>>> > >> On 15/12/15 08:49, Shannon Zhao wrote:
>>>>>> > >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
>>>>>> > >>>>
>>>>>> > >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>>>>>> > >>>> the kvm_device_ops for it.
>>>>>> > >>>>
>>>>>> > >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>>>>>> > >>>> ---
>>>>>> > >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>>>>>> > >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>>>>>> > >>>>  include/linux/kvm_host.h                      |   1 +
>>>>>> > >>>>  include/uapi/linux/kvm.h                      |   2 +
>>>>>> > >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>>>>>> > >>>>  virt/kvm/kvm_main.c                           |   4 +
>>>>>> > >>>>  6 files changed, 141 insertions(+)
>>>>>> > >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>> new file mode 100644
>>>>>> > >>>> index 0000000..5121f1f
>>>>>> > >>>> --- /dev/null
>>>>>> > >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>> @@ -0,0 +1,16 @@
>>>>>> > >>>> +ARM Virtual Performance Monitor Unit (vPMU)
>>>>>> > >>>> +===========================================
>>>>>> > >>>> +
>>>>>> > >>>> +Device types supported:
>>>>>> > >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>> > >>>> +
>>>>>> > >>>> +Instantiate one PMU instance for per VCPU through this API.
>>>>>> > >>>> +
>>>>>> > >>>> +Groups:
>>>>>> > >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>> > >>>> +  Attributes:
>>>>>> > >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
>>>>>> > >>>> +    interrupt should be a PPI.
>>>>>> > >>>> +
>>>>>> > >>>> +  Errors:
>>>>>> > >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
>>>>>> > >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> index 2d4ca4b..568afa2 100644
>>>>>> > >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>>>>>> > >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>>>>>> > >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>>>>>> > >>>>
>>>>>> > >>>> +/* Device Control API: ARM PMU */
>>>>>> > >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
>>>>>> > >>>> +
>>>>>> > >>>>  /* KVM_IRQ_LINE irq field index values */
>>>>>> > >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>>>>>> > >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
>>>>>> > >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>>>>>> > >>>> index c923350..608dea6 100644
>>>>>> > >>>> --- a/include/linux/kvm_host.h
>>>>>> > >>>> +++ b/include/linux/kvm_host.h
>>>>>> > >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_xics_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>>>>>> > >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>>>>>> > >>>>
>>>>>> > >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>>>> > >>>> index 03f3618..4ba6fdd 100644
>>>>>> > >>>> --- a/include/uapi/linux/kvm.h
>>>>>> > >>>> +++ b/include/uapi/linux/kvm.h
>>>>>> > >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>>>>>> > >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>>>>>> > >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
>>>>>> > >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
>>>>>> > >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
>>>>>> > >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>>>>>> > >>>>  	KVM_DEV_TYPE_MAX,
>>>>>> > >>>>  };
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>>>>>> > >>>> index d113ee4..1965d0d 100644
>>>>>> > >>>> --- a/virt/kvm/arm/pmu.c
>>>>>> > >>>> +++ b/virt/kvm/arm/pmu.c
>>>>>> > >>>> @@ -19,6 +19,7 @@
>>>>>> > >>>>  #include <linux/kvm.h>
>>>>>> > >>>>  #include <linux/kvm_host.h>
>>>>>> > >>>>  #include <linux/perf_event.h>
>>>>>> > >>>> +#include <linux/uaccess.h>
>>>>>> > >>>>  #include <asm/kvm_emulate.h>
>>>>>> > >>>>  #include <kvm/arm_pmu.h>
>>>>>> > >>>>  #include <kvm/arm_vgic.h>
>>>>>> > >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>>>>>> > >>>>
>>>>>> > >>>>  	pmc->perf_event = event;
>>>>>> > >>>>  }
>>>>>> > >>>> +
>>>>>> > >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>>>>>> > >>>> +{
>>>>>> > >>>> +	return vcpu->arch.pmu.irq_num != -1;
>>>>>> > >>>> +}
>>>>>> > >>>> +
>>>>>> > >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>>>>>> > >>>> +{
>>>>>> > >>>> +	int j;
>>>>>> > >>>> +	struct kvm_vcpu *vcpu;
>>>>>> > >>>> +
>>>>>> > >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
>>>>>> > >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
>>>>>> > >>>> +
>>>>>> > >>>> +		if (!is_set) {
>>>>>> > >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
>>>>>> > >>>> +				return -EBUSY;
>>>> > >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
>>>> > >> anyway. Actually, why would you return an error in this case?
>>>> > >>
>>> > > While this is a unexpected operation from user space and it's already 
>>> > > initialized and working, so I think it should return an error to user 
>>> > > and tell user that it's already initialized and working (this should 
>>> > > mean "busy" ?).
>> > 
>> > But in this case, you're returning an error if it is *not* initialized.
>> > I understand that in that case you cannot return an interrupt number (-1
>> > would be weird), but returning -EBUSY feels even more weird.
>> > 
>> > I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>> > 
> ENXIO or ENODEV would be my choice too, and add that to the
> Documentation clearly describing when this error code is used.
> 
> By the way, why do you loop over all VCPUS to set the same value when
> you can't do anything per VCPU anyway?  It seems to me it's either a
> per-VM property (that you can store on the VM data structure) or it's a
> true per-VCPU property?

This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
the interrupt numbers are same for each vcpu, while for SPI they are
different, so it needs to set them separately. I planned to support both
PPI and SPI. I think I should add support for SPI at this moment and let
users (QEMU) to set these interrupts for each one.

Thanks,
-- 
Shannon


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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-16  7:31             ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  7:31 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/16 4:47, Christoffer Dall wrote:
> On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
>> > On 15/12/15 15:50, Shannon Zhao wrote:
>>> > > 
>>> > > 
>>> > > On 2015/12/15 23:33, Marc Zyngier wrote:
>>>> > >> On 15/12/15 08:49, Shannon Zhao wrote:
>>>>>> > >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
>>>>>> > >>>>
>>>>>> > >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>>>>>> > >>>> the kvm_device_ops for it.
>>>>>> > >>>>
>>>>>> > >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>>>>>> > >>>> ---
>>>>>> > >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>>>>>> > >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>>>>>> > >>>>  include/linux/kvm_host.h                      |   1 +
>>>>>> > >>>>  include/uapi/linux/kvm.h                      |   2 +
>>>>>> > >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>>>>>> > >>>>  virt/kvm/kvm_main.c                           |   4 +
>>>>>> > >>>>  6 files changed, 141 insertions(+)
>>>>>> > >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>> new file mode 100644
>>>>>> > >>>> index 0000000..5121f1f
>>>>>> > >>>> --- /dev/null
>>>>>> > >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>> @@ -0,0 +1,16 @@
>>>>>> > >>>> +ARM Virtual Performance Monitor Unit (vPMU)
>>>>>> > >>>> +===========================================
>>>>>> > >>>> +
>>>>>> > >>>> +Device types supported:
>>>>>> > >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>> > >>>> +
>>>>>> > >>>> +Instantiate one PMU instance for per VCPU through this API.
>>>>>> > >>>> +
>>>>>> > >>>> +Groups:
>>>>>> > >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>> > >>>> +  Attributes:
>>>>>> > >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
>>>>>> > >>>> +    interrupt should be a PPI.
>>>>>> > >>>> +
>>>>>> > >>>> +  Errors:
>>>>>> > >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
>>>>>> > >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> index 2d4ca4b..568afa2 100644
>>>>>> > >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>>>>>> > >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>>>>>> > >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>>>>>> > >>>>
>>>>>> > >>>> +/* Device Control API: ARM PMU */
>>>>>> > >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
>>>>>> > >>>> +
>>>>>> > >>>>  /* KVM_IRQ_LINE irq field index values */
>>>>>> > >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>>>>>> > >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
>>>>>> > >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>>>>>> > >>>> index c923350..608dea6 100644
>>>>>> > >>>> --- a/include/linux/kvm_host.h
>>>>>> > >>>> +++ b/include/linux/kvm_host.h
>>>>>> > >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_xics_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>>>>>> > >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>>>>>> > >>>>
>>>>>> > >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>>>> > >>>> index 03f3618..4ba6fdd 100644
>>>>>> > >>>> --- a/include/uapi/linux/kvm.h
>>>>>> > >>>> +++ b/include/uapi/linux/kvm.h
>>>>>> > >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>>>>>> > >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>>>>>> > >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
>>>>>> > >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
>>>>>> > >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
>>>>>> > >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>>>>>> > >>>>  	KVM_DEV_TYPE_MAX,
>>>>>> > >>>>  };
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>>>>>> > >>>> index d113ee4..1965d0d 100644
>>>>>> > >>>> --- a/virt/kvm/arm/pmu.c
>>>>>> > >>>> +++ b/virt/kvm/arm/pmu.c
>>>>>> > >>>> @@ -19,6 +19,7 @@
>>>>>> > >>>>  #include <linux/kvm.h>
>>>>>> > >>>>  #include <linux/kvm_host.h>
>>>>>> > >>>>  #include <linux/perf_event.h>
>>>>>> > >>>> +#include <linux/uaccess.h>
>>>>>> > >>>>  #include <asm/kvm_emulate.h>
>>>>>> > >>>>  #include <kvm/arm_pmu.h>
>>>>>> > >>>>  #include <kvm/arm_vgic.h>
>>>>>> > >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>>>>>> > >>>>
>>>>>> > >>>>  	pmc->perf_event = event;
>>>>>> > >>>>  }
>>>>>> > >>>> +
>>>>>> > >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>>>>>> > >>>> +{
>>>>>> > >>>> +	return vcpu->arch.pmu.irq_num != -1;
>>>>>> > >>>> +}
>>>>>> > >>>> +
>>>>>> > >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>>>>>> > >>>> +{
>>>>>> > >>>> +	int j;
>>>>>> > >>>> +	struct kvm_vcpu *vcpu;
>>>>>> > >>>> +
>>>>>> > >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
>>>>>> > >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
>>>>>> > >>>> +
>>>>>> > >>>> +		if (!is_set) {
>>>>>> > >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
>>>>>> > >>>> +				return -EBUSY;
>>>> > >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
>>>> > >> anyway. Actually, why would you return an error in this case?
>>>> > >>
>>> > > While this is a unexpected operation from user space and it's already 
>>> > > initialized and working, so I think it should return an error to user 
>>> > > and tell user that it's already initialized and working (this should 
>>> > > mean "busy" ?).
>> > 
>> > But in this case, you're returning an error if it is *not* initialized.
>> > I understand that in that case you cannot return an interrupt number (-1
>> > would be weird), but returning -EBUSY feels even more weird.
>> > 
>> > I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>> > 
> ENXIO or ENODEV would be my choice too, and add that to the
> Documentation clearly describing when this error code is used.
> 
> By the way, why do you loop over all VCPUS to set the same value when
> you can't do anything per VCPU anyway?  It seems to me it's either a
> per-VM property (that you can store on the VM data structure) or it's a
> true per-VCPU property?

This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
the interrupt numbers are same for each vcpu, while for SPI they are
different, so it needs to set them separately. I planned to support both
PPI and SPI. I think I should add support for SPI at this moment and let
users (QEMU) to set these interrupts for each one.

Thanks,
-- 
Shannon


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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-16  7:31             ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  7:31 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/16 4:47, Christoffer Dall wrote:
> On Tue, Dec 15, 2015 at 03:59:31PM +0000, Marc Zyngier wrote:
>> > On 15/12/15 15:50, Shannon Zhao wrote:
>>> > > 
>>> > > 
>>> > > On 2015/12/15 23:33, Marc Zyngier wrote:
>>>> > >> On 15/12/15 08:49, Shannon Zhao wrote:
>>>>>> > >>>> From: Shannon Zhao<shannon.zhao@linaro.org>
>>>>>> > >>>>
>>>>>> > >>>> Add a new kvm device type KVM_DEV_TYPE_ARM_PMU_V3 for ARM PMU. Implement
>>>>>> > >>>> the kvm_device_ops for it.
>>>>>> > >>>>
>>>>>> > >>>> Signed-off-by: Shannon Zhao<shannon.zhao@linaro.org>
>>>>>> > >>>> ---
>>>>>> > >>>>  Documentation/virtual/kvm/devices/arm-pmu.txt |  16 ++++
>>>>>> > >>>>  arch/arm64/include/uapi/asm/kvm.h             |   3 +
>>>>>> > >>>>  include/linux/kvm_host.h                      |   1 +
>>>>>> > >>>>  include/uapi/linux/kvm.h                      |   2 +
>>>>>> > >>>>  virt/kvm/arm/pmu.c                            | 115 ++++++++++++++++++++++++++
>>>>>> > >>>>  virt/kvm/kvm_main.c                           |   4 +
>>>>>> > >>>>  6 files changed, 141 insertions(+)
>>>>>> > >>>>  create mode 100644 Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/Documentation/virtual/kvm/devices/arm-pmu.txt b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>> new file mode 100644
>>>>>> > >>>> index 0000000..5121f1f
>>>>>> > >>>> --- /dev/null
>>>>>> > >>>> +++ b/Documentation/virtual/kvm/devices/arm-pmu.txt
>>>>>> > >>>> @@ -0,0 +1,16 @@
>>>>>> > >>>> +ARM Virtual Performance Monitor Unit (vPMU)
>>>>>> > >>>> +===========================================
>>>>>> > >>>> +
>>>>>> > >>>> +Device types supported:
>>>>>> > >>>> +  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>> > >>>> +
>>>>>> > >>>> +Instantiate one PMU instance for per VCPU through this API.
>>>>>> > >>>> +
>>>>>> > >>>> +Groups:
>>>>>> > >>>> +  KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>> > >>>> +  Attributes:
>>>>>> > >>>> +    A value describing the interrupt number of PMU overflow interrupt. This
>>>>>> > >>>> +    interrupt should be a PPI.
>>>>>> > >>>> +
>>>>>> > >>>> +  Errors:
>>>>>> > >>>> +    -EINVAL: Value set is out of the expected range (from 16 to 31)
>>>>>> > >>>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> index 2d4ca4b..568afa2 100644
>>>>>> > >>>> --- a/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>>>>>> > >>>> @@ -204,6 +204,9 @@ struct kvm_arch_memory_slot {
>>>>>> > >>>>  #define KVM_DEV_ARM_VGIC_GRP_CTRL	4
>>>>>> > >>>>  #define   KVM_DEV_ARM_VGIC_CTRL_INIT	0
>>>>>> > >>>>
>>>>>> > >>>> +/* Device Control API: ARM PMU */
>>>>>> > >>>> +#define KVM_DEV_ARM_PMU_GRP_IRQ		0
>>>>>> > >>>> +
>>>>>> > >>>>  /* KVM_IRQ_LINE irq field index values */
>>>>>> > >>>>  #define KVM_ARM_IRQ_TYPE_SHIFT		24
>>>>>> > >>>>  #define KVM_ARM_IRQ_TYPE_MASK		0xff
>>>>>> > >>>> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
>>>>>> > >>>> index c923350..608dea6 100644
>>>>>> > >>>> --- a/include/linux/kvm_host.h
>>>>>> > >>>> +++ b/include/linux/kvm_host.h
>>>>>> > >>>> @@ -1161,6 +1161,7 @@ extern struct kvm_device_ops kvm_mpic_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_xics_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_arm_vgic_v2_ops;
>>>>>> > >>>>  extern struct kvm_device_ops kvm_arm_vgic_v3_ops;
>>>>>> > >>>> +extern struct kvm_device_ops kvm_arm_pmu_ops;
>>>>>> > >>>>
>>>>>> > >>>>  #ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
>>>>>> > >>>> index 03f3618..4ba6fdd 100644
>>>>>> > >>>> --- a/include/uapi/linux/kvm.h
>>>>>> > >>>> +++ b/include/uapi/linux/kvm.h
>>>>>> > >>>> @@ -1032,6 +1032,8 @@ enum kvm_device_type {
>>>>>> > >>>>  #define KVM_DEV_TYPE_FLIC		KVM_DEV_TYPE_FLIC
>>>>>> > >>>>  	KVM_DEV_TYPE_ARM_VGIC_V3,
>>>>>> > >>>>  #define KVM_DEV_TYPE_ARM_VGIC_V3	KVM_DEV_TYPE_ARM_VGIC_V3
>>>>>> > >>>> +	KVM_DEV_TYPE_ARM_PMU_V3,
>>>>>> > >>>> +#define	KVM_DEV_TYPE_ARM_PMU_V3		KVM_DEV_TYPE_ARM_PMU_V3
>>>>>> > >>>>  	KVM_DEV_TYPE_MAX,
>>>>>> > >>>>  };
>>>>>> > >>>>
>>>>>> > >>>> diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c
>>>>>> > >>>> index d113ee4..1965d0d 100644
>>>>>> > >>>> --- a/virt/kvm/arm/pmu.c
>>>>>> > >>>> +++ b/virt/kvm/arm/pmu.c
>>>>>> > >>>> @@ -19,6 +19,7 @@
>>>>>> > >>>>  #include <linux/kvm.h>
>>>>>> > >>>>  #include <linux/kvm_host.h>
>>>>>> > >>>>  #include <linux/perf_event.h>
>>>>>> > >>>> +#include <linux/uaccess.h>
>>>>>> > >>>>  #include <asm/kvm_emulate.h>
>>>>>> > >>>>  #include <kvm/arm_pmu.h>
>>>>>> > >>>>  #include <kvm/arm_vgic.h>
>>>>>> > >>>> @@ -357,3 +358,117 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>>>>>> > >>>>
>>>>>> > >>>>  	pmc->perf_event = event;
>>>>>> > >>>>  }
>>>>>> > >>>> +
>>>>>> > >>>> +static inline bool kvm_arm_pmu_initialized(struct kvm_vcpu *vcpu)
>>>>>> > >>>> +{
>>>>>> > >>>> +	return vcpu->arch.pmu.irq_num != -1;
>>>>>> > >>>> +}
>>>>>> > >>>> +
>>>>>> > >>>> +static int kvm_arm_pmu_irq_access(struct kvm *kvm, int *irq, bool is_set)
>>>>>> > >>>> +{
>>>>>> > >>>> +	int j;
>>>>>> > >>>> +	struct kvm_vcpu *vcpu;
>>>>>> > >>>> +
>>>>>> > >>>> +	kvm_for_each_vcpu(j, vcpu, kvm) {
>>>>>> > >>>> +		struct kvm_pmu *pmu = &vcpu->arch.pmu;
>>>>>> > >>>> +
>>>>>> > >>>> +		if (!is_set) {
>>>>>> > >>>> +			if (!kvm_arm_pmu_initialized(vcpu))
>>>>>> > >>>> +				return -EBUSY;
>>>> > >> Returning -EBUSY is a bit odd. Maybe -EINVAL? But this seems weird
>>>> > >> anyway. Actually, why would you return an error in this case?
>>>> > >>
>>> > > While this is a unexpected operation from user space and it's already 
>>> > > initialized and working, so I think it should return an error to user 
>>> > > and tell user that it's already initialized and working (this should 
>>> > > mean "busy" ?).
>> > 
>> > But in this case, you're returning an error if it is *not* initialized.
>> > I understand that in that case you cannot return an interrupt number (-1
>> > would be weird), but returning -EBUSY feels even more weird.
>> > 
>> > I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>> > 
> ENXIO or ENODEV would be my choice too, and add that to the
> Documentation clearly describing when this error code is used.
> 
> By the way, why do you loop over all VCPUS to set the same value when
> you can't do anything per VCPU anyway?  It seems to me it's either a
> per-VM property (that you can store on the VM data structure) or it's a
> true per-VCPU property?

This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
the interrupt numbers are same for each vcpu, while for SPI they are
different, so it needs to set them separately. I planned to support both
PPI and SPI. I think I should add support for SPI at this moment and let
users (QEMU) to set these interrupts for each one.

Thanks,
-- 
Shannon

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-16  7:31             ` Shannon Zhao
@ 2015-12-16  8:06               ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  8:06 UTC (permalink / raw)
  To: Christoffer Dall, Marc Zyngier
  Cc: kvm, will.deacon, Shannon Zhao, kvmarm, linux-arm-kernel

Hi,

On 2015/12/16 15:31, Shannon Zhao wrote:
>>>> >> > But in this case, you're returning an error if it is *not* initialized.
>>>> >> > I understand that in that case you cannot return an interrupt number (-1
>>>> >> > would be weird), but returning -EBUSY feels even more weird.
>>>> >> > 
>>>> >> > I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>> >> > 
>> > ENXIO or ENODEV would be my choice too, and add that to the
>> > Documentation clearly describing when this error code is used.
>> > 
>> > By the way, why do you loop over all VCPUS to set the same value when
>> > you can't do anything per VCPU anyway?  It seems to me it's either a
>> > per-VM property (that you can store on the VM data structure) or it's a
>> > true per-VCPU property?
> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> the interrupt numbers are same for each vcpu, while for SPI they are
> different, so it needs to set them separately. I planned to support both
> PPI and SPI. I think I should add support for SPI at this moment and let
> users (QEMU) to set these interrupts for each one.

How about below vPMU Documentation?

ARM Virtual Performance Monitor Unit (vPMU)
===========================================

Device types supported:
  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3

Instantiate one PMU instance for per VCPU through this API.

Groups:
  KVM_DEV_ARM_PMU_GRP_IRQ
  Attributes:
    The attr field of kvm_device_attr encodes two values:
    bits:     | 63 .... 32 | 31 .... 0 |
    values:   | vcpu_index |  irq_num  |
    The irq_num describes the PMU overflow interrupt number for the
specified
    vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
VM the
    interrupt type must be same for each vcpu.

  Errors:
    -ENXIO: Getting or setting this attribute is not yet supported
    -ENODEV: Getting the PMU overflow interrupt number while it's not set
    -EBUSY: The PMU overflow interrupt is already set
    -EINVAL: Invalid vcpu_index or irq_num supplied


-- 
Shannon

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-16  8:06               ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  8:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On 2015/12/16 15:31, Shannon Zhao wrote:
>>>> >> > But in this case, you're returning an error if it is *not* initialized.
>>>> >> > I understand that in that case you cannot return an interrupt number (-1
>>>> >> > would be weird), but returning -EBUSY feels even more weird.
>>>> >> > 
>>>> >> > I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>> >> > 
>> > ENXIO or ENODEV would be my choice too, and add that to the
>> > Documentation clearly describing when this error code is used.
>> > 
>> > By the way, why do you loop over all VCPUS to set the same value when
>> > you can't do anything per VCPU anyway?  It seems to me it's either a
>> > per-VM property (that you can store on the VM data structure) or it's a
>> > true per-VCPU property?
> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> the interrupt numbers are same for each vcpu, while for SPI they are
> different, so it needs to set them separately. I planned to support both
> PPI and SPI. I think I should add support for SPI at this moment and let
> users (QEMU) to set these interrupts for each one.

How about below vPMU Documentation?

ARM Virtual Performance Monitor Unit (vPMU)
===========================================

Device types supported:
  KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3

Instantiate one PMU instance for per VCPU through this API.

Groups:
  KVM_DEV_ARM_PMU_GRP_IRQ
  Attributes:
    The attr field of kvm_device_attr encodes two values:
    bits:     | 63 .... 32 | 31 .... 0 |
    values:   | vcpu_index |  irq_num  |
    The irq_num describes the PMU overflow interrupt number for the
specified
    vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
VM the
    interrupt type must be same for each vcpu.

  Errors:
    -ENXIO: Getting or setting this attribute is not yet supported
    -ENODEV: Getting the PMU overflow interrupt number while it's not set
    -EBUSY: The PMU overflow interrupt is already set
    -EINVAL: Invalid vcpu_index or irq_num supplied


-- 
Shannon

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-16  8:06               ` Shannon Zhao
@ 2015-12-16  9:04                 ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-16  9:04 UTC (permalink / raw)
  To: Shannon Zhao, Christoffer Dall
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai

On 16/12/15 08:06, Shannon Zhao wrote:
> Hi,
> 
> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>
>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>
>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>> Documentation clearly describing when this error code is used.
>>>>
>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>> true per-VCPU property?
>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>> the interrupt numbers are same for each vcpu, while for SPI they are
>> different, so it needs to set them separately. I planned to support both
>> PPI and SPI. I think I should add support for SPI at this moment and let
>> users (QEMU) to set these interrupts for each one.
> 
> How about below vPMU Documentation?
> 
> ARM Virtual Performance Monitor Unit (vPMU)
> ===========================================
> 
> Device types supported:
>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> 
> Instantiate one PMU instance for per VCPU through this API.
> 
> Groups:
>   KVM_DEV_ARM_PMU_GRP_IRQ
>   Attributes:
>     The attr field of kvm_device_attr encodes two values:
>     bits:     | 63 .... 32 | 31 .... 0 |
>     values:   | vcpu_index |  irq_num  |
>     The irq_num describes the PMU overflow interrupt number for the
> specified
>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
> VM the
>     interrupt type must be same for each vcpu.
> 
>   Errors:
>     -ENXIO: Getting or setting this attribute is not yet supported
>     -ENODEV: Getting the PMU overflow interrupt number while it's not set
>     -EBUSY: The PMU overflow interrupt is already set
>     -EINVAL: Invalid vcpu_index or irq_num supplied
> 
> 

Let's add at least one comment that forbids two vcpus from getting the
same SPI. This is too common a mistake that we see in actual SoCs, and I
don't want to see it replicated in VMs...

Thanks,

	M.

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

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-16  9:04                 ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-16  9:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 16/12/15 08:06, Shannon Zhao wrote:
> Hi,
> 
> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>
>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>
>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>> Documentation clearly describing when this error code is used.
>>>>
>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>> true per-VCPU property?
>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>> the interrupt numbers are same for each vcpu, while for SPI they are
>> different, so it needs to set them separately. I planned to support both
>> PPI and SPI. I think I should add support for SPI at this moment and let
>> users (QEMU) to set these interrupts for each one.
> 
> How about below vPMU Documentation?
> 
> ARM Virtual Performance Monitor Unit (vPMU)
> ===========================================
> 
> Device types supported:
>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> 
> Instantiate one PMU instance for per VCPU through this API.
> 
> Groups:
>   KVM_DEV_ARM_PMU_GRP_IRQ
>   Attributes:
>     The attr field of kvm_device_attr encodes two values:
>     bits:     | 63 .... 32 | 31 .... 0 |
>     values:   | vcpu_index |  irq_num  |
>     The irq_num describes the PMU overflow interrupt number for the
> specified
>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
> VM the
>     interrupt type must be same for each vcpu.
> 
>   Errors:
>     -ENXIO: Getting or setting this attribute is not yet supported
>     -ENODEV: Getting the PMU overflow interrupt number while it's not set
>     -EBUSY: The PMU overflow interrupt is already set
>     -EINVAL: Invalid vcpu_index or irq_num supplied
> 
> 

Let's add at least one comment that forbids two vcpus from getting the
same SPI. This is too common a mistake that we see in actual SoCs, and I
don't want to see it replicated in VMs...

Thanks,

	M.

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

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-16  9:04                 ` Marc Zyngier
  (?)
@ 2015-12-16  9:29                   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  9:29 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/16 17:04, Marc Zyngier wrote:
> On 16/12/15 08:06, Shannon Zhao wrote:
>> > Hi,
>> > 
>> > On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>> >>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>> >>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>> >>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>> >>>>>>>>
>>>>> >>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>> >>>> Documentation clearly describing when this error code is used.
>>>>> >>>>
>>>>> >>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>> >>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>> >>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>> >>>> true per-VCPU property?
>>> >> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>> >> the interrupt numbers are same for each vcpu, while for SPI they are
>>> >> different, so it needs to set them separately. I planned to support both
>>> >> PPI and SPI. I think I should add support for SPI at this moment and let
>>> >> users (QEMU) to set these interrupts for each one.
>> > 
>> > How about below vPMU Documentation?
>> > 
>> > ARM Virtual Performance Monitor Unit (vPMU)
>> > ===========================================
>> > 
>> > Device types supported:
>> >   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>> > 
>> > Instantiate one PMU instance for per VCPU through this API.
>> > 
>> > Groups:
>> >   KVM_DEV_ARM_PMU_GRP_IRQ
>> >   Attributes:
>> >     The attr field of kvm_device_attr encodes two values:
>> >     bits:     | 63 .... 32 | 31 .... 0 |
>> >     values:   | vcpu_index |  irq_num  |
>> >     The irq_num describes the PMU overflow interrupt number for the
>> > specified
>> >     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
>> > VM the
>> >     interrupt type must be same for each vcpu.
>> > 
>> >   Errors:
>> >     -ENXIO: Getting or setting this attribute is not yet supported
>> >     -ENODEV: Getting the PMU overflow interrupt number while it's not set
>> >     -EBUSY: The PMU overflow interrupt is already set
>> >     -EINVAL: Invalid vcpu_index or irq_num supplied
>> > 
>> > 
> Let's add at least one comment that forbids two vcpus from getting the
> same SPI. This is too common a mistake that we see in actual SoCs, and I
> don't want to see it replicated in VMs...

Ok, will add.

Thanks,
-- 
Shannon


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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-16  9:29                   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  9:29 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/16 17:04, Marc Zyngier wrote:
> On 16/12/15 08:06, Shannon Zhao wrote:
>> > Hi,
>> > 
>> > On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>> >>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>> >>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>> >>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>> >>>>>>>>
>>>>> >>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>> >>>> Documentation clearly describing when this error code is used.
>>>>> >>>>
>>>>> >>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>> >>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>> >>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>> >>>> true per-VCPU property?
>>> >> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>> >> the interrupt numbers are same for each vcpu, while for SPI they are
>>> >> different, so it needs to set them separately. I planned to support both
>>> >> PPI and SPI. I think I should add support for SPI at this moment and let
>>> >> users (QEMU) to set these interrupts for each one.
>> > 
>> > How about below vPMU Documentation?
>> > 
>> > ARM Virtual Performance Monitor Unit (vPMU)
>> > ===========================================
>> > 
>> > Device types supported:
>> >   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>> > 
>> > Instantiate one PMU instance for per VCPU through this API.
>> > 
>> > Groups:
>> >   KVM_DEV_ARM_PMU_GRP_IRQ
>> >   Attributes:
>> >     The attr field of kvm_device_attr encodes two values:
>> >     bits:     | 63 .... 32 | 31 .... 0 |
>> >     values:   | vcpu_index |  irq_num  |
>> >     The irq_num describes the PMU overflow interrupt number for the
>> > specified
>> >     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
>> > VM the
>> >     interrupt type must be same for each vcpu.
>> > 
>> >   Errors:
>> >     -ENXIO: Getting or setting this attribute is not yet supported
>> >     -ENODEV: Getting the PMU overflow interrupt number while it's not set
>> >     -EBUSY: The PMU overflow interrupt is already set
>> >     -EINVAL: Invalid vcpu_index or irq_num supplied
>> > 
>> > 
> Let's add at least one comment that forbids two vcpus from getting the
> same SPI. This is too common a mistake that we see in actual SoCs, and I
> don't want to see it replicated in VMs...

Ok, will add.

Thanks,
-- 
Shannon


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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-16  9:29                   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-16  9:29 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/16 17:04, Marc Zyngier wrote:
> On 16/12/15 08:06, Shannon Zhao wrote:
>> > Hi,
>> > 
>> > On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>> >>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>> >>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>> >>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>> >>>>>>>>
>>>>> >>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>> >>>> Documentation clearly describing when this error code is used.
>>>>> >>>>
>>>>> >>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>> >>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>> >>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>> >>>> true per-VCPU property?
>>> >> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>> >> the interrupt numbers are same for each vcpu, while for SPI they are
>>> >> different, so it needs to set them separately. I planned to support both
>>> >> PPI and SPI. I think I should add support for SPI at this moment and let
>>> >> users (QEMU) to set these interrupts for each one.
>> > 
>> > How about below vPMU Documentation?
>> > 
>> > ARM Virtual Performance Monitor Unit (vPMU)
>> > ===========================================
>> > 
>> > Device types supported:
>> >   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>> > 
>> > Instantiate one PMU instance for per VCPU through this API.
>> > 
>> > Groups:
>> >   KVM_DEV_ARM_PMU_GRP_IRQ
>> >   Attributes:
>> >     The attr field of kvm_device_attr encodes two values:
>> >     bits:     | 63 .... 32 | 31 .... 0 |
>> >     values:   | vcpu_index |  irq_num  |
>> >     The irq_num describes the PMU overflow interrupt number for the
>> > specified
>> >     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
>> > VM the
>> >     interrupt type must be same for each vcpu.
>> > 
>> >   Errors:
>> >     -ENXIO: Getting or setting this attribute is not yet supported
>> >     -ENODEV: Getting the PMU overflow interrupt number while it's not set
>> >     -EBUSY: The PMU overflow interrupt is already set
>> >     -EINVAL: Invalid vcpu_index or irq_num supplied
>> > 
>> > 
> Let's add at least one comment that forbids two vcpus from getting the
> same SPI. This is too common a mistake that we see in actual SoCs, and I
> don't want to see it replicated in VMs...

Ok, will add.

Thanks,
-- 
Shannon

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-16  8:06               ` Shannon Zhao
@ 2015-12-16 20:33                 ` Christoffer Dall
  -1 siblings, 0 replies; 135+ messages in thread
From: Christoffer Dall @ 2015-12-16 20:33 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: kvm, Marc Zyngier, will.deacon, Shannon Zhao, kvmarm, linux-arm-kernel

On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> Hi,
> 
> On 2015/12/16 15:31, Shannon Zhao wrote:
> >>>> >> > But in this case, you're returning an error if it is *not* initialized.
> >>>> >> > I understand that in that case you cannot return an interrupt number (-1
> >>>> >> > would be weird), but returning -EBUSY feels even more weird.
> >>>> >> > 
> >>>> >> > I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> >>>> >> > 
> >> > ENXIO or ENODEV would be my choice too, and add that to the
> >> > Documentation clearly describing when this error code is used.
> >> > 
> >> > By the way, why do you loop over all VCPUS to set the same value when
> >> > you can't do anything per VCPU anyway?  It seems to me it's either a
> >> > per-VM property (that you can store on the VM data structure) or it's a
> >> > true per-VCPU property?
> > This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> > the interrupt numbers are same for each vcpu, while for SPI they are
> > different, so it needs to set them separately. I planned to support both
> > PPI and SPI. I think I should add support for SPI at this moment and let
> > users (QEMU) to set these interrupts for each one.
> 
> How about below vPMU Documentation?
> 
> ARM Virtual Performance Monitor Unit (vPMU)
> ===========================================
> 
> Device types supported:
>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> 
> Instantiate one PMU instance for per VCPU through this API.
> 
> Groups:
>   KVM_DEV_ARM_PMU_GRP_IRQ
>   Attributes:
>     The attr field of kvm_device_attr encodes two values:
>     bits:     | 63 .... 32 | 31 .... 0 |
>     values:   | vcpu_index |  irq_num  |
>     The irq_num describes the PMU overflow interrupt number for the
> specified
>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
> VM the
>     interrupt type must be same for each vcpu.

some formatting snafus that I expect come from pasting the text in an
e-mail client.

> 
>   Errors:
>     -ENXIO: Getting or setting this attribute is not yet supported

'not yet supported' as in something we'll implement later, or as in you
need to call this other function before you can access this state?

>     -ENODEV: Getting the PMU overflow interrupt number while it's not set
>     -EBUSY: The PMU overflow interrupt is already set
>     -EINVAL: Invalid vcpu_index or irq_num supplied
> 
> 
Otherwise looks good.

Thanks,
-Christoffer

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-16 20:33                 ` Christoffer Dall
  0 siblings, 0 replies; 135+ messages in thread
From: Christoffer Dall @ 2015-12-16 20:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> Hi,
> 
> On 2015/12/16 15:31, Shannon Zhao wrote:
> >>>> >> > But in this case, you're returning an error if it is *not* initialized.
> >>>> >> > I understand that in that case you cannot return an interrupt number (-1
> >>>> >> > would be weird), but returning -EBUSY feels even more weird.
> >>>> >> > 
> >>>> >> > I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> >>>> >> > 
> >> > ENXIO or ENODEV would be my choice too, and add that to the
> >> > Documentation clearly describing when this error code is used.
> >> > 
> >> > By the way, why do you loop over all VCPUS to set the same value when
> >> > you can't do anything per VCPU anyway?  It seems to me it's either a
> >> > per-VM property (that you can store on the VM data structure) or it's a
> >> > true per-VCPU property?
> > This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> > the interrupt numbers are same for each vcpu, while for SPI they are
> > different, so it needs to set them separately. I planned to support both
> > PPI and SPI. I think I should add support for SPI at this moment and let
> > users (QEMU) to set these interrupts for each one.
> 
> How about below vPMU Documentation?
> 
> ARM Virtual Performance Monitor Unit (vPMU)
> ===========================================
> 
> Device types supported:
>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> 
> Instantiate one PMU instance for per VCPU through this API.
> 
> Groups:
>   KVM_DEV_ARM_PMU_GRP_IRQ
>   Attributes:
>     The attr field of kvm_device_attr encodes two values:
>     bits:     | 63 .... 32 | 31 .... 0 |
>     values:   | vcpu_index |  irq_num  |
>     The irq_num describes the PMU overflow interrupt number for the
> specified
>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
> VM the
>     interrupt type must be same for each vcpu.

some formatting snafus that I expect come from pasting the text in an
e-mail client.

> 
>   Errors:
>     -ENXIO: Getting or setting this attribute is not yet supported

'not yet supported' as in something we'll implement later, or as in you
need to call this other function before you can access this state?

>     -ENODEV: Getting the PMU overflow interrupt number while it's not set
>     -EBUSY: The PMU overflow interrupt is already set
>     -EINVAL: Invalid vcpu_index or irq_num supplied
> 
> 
Otherwise looks good.

Thanks,
-Christoffer

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-16 20:33                 ` Christoffer Dall
  (?)
@ 2015-12-17  7:22                   ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17  7:22 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Marc Zyngier, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/17 4:33, Christoffer Dall wrote:
> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>> Hi,
>>
>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>
>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>
>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>> Documentation clearly describing when this error code is used.
>>>>>
>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>> true per-VCPU property?
>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>> different, so it needs to set them separately. I planned to support both
>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>> users (QEMU) to set these interrupts for each one.
>>
>> How about below vPMU Documentation?
>>
>> ARM Virtual Performance Monitor Unit (vPMU)
>> ===========================================
>>
>> Device types supported:
>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>
>> Instantiate one PMU instance for per VCPU through this API.
>>
>> Groups:
>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>   Attributes:
>>     The attr field of kvm_device_attr encodes two values:
>>     bits:     | 63 .... 32 | 31 .... 0 |
>>     values:   | vcpu_index |  irq_num  |
BTW, I change this Attribute to below format and pass vcpu_index through
this Attribute while pass irq_num through kvm_device_attr.addr.
Is it fine?

    bits:     | 63 .... 32 | 31 ....  0 |
    values:   |  reserved  | vcpu_index |

>>     The irq_num describes the PMU overflow interrupt number for the
>> specified
>>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
>> VM the
>>     interrupt type must be same for each vcpu.
> 
> some formatting snafus that I expect come from pasting the text in an
> e-mail client.
> 
>>
>>   Errors:
>>     -ENXIO: Getting or setting this attribute is not yet supported
> 
> 'not yet supported' as in something we'll implement later, or as in you
> need to call this other function before you can access this state?
> 
Since only when the group is not KVM_DEV_ARM_PMU_GRP_IRQ, it will return
-ENXIO. So what about this?

"-ENXIO: Unsupported attribute group"

Thanks,
-- 
Shannon


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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17  7:22                   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17  7:22 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Marc Zyngier, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/17 4:33, Christoffer Dall wrote:
> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>> Hi,
>>
>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>
>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>
>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>> Documentation clearly describing when this error code is used.
>>>>>
>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>> true per-VCPU property?
>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>> different, so it needs to set them separately. I planned to support both
>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>> users (QEMU) to set these interrupts for each one.
>>
>> How about below vPMU Documentation?
>>
>> ARM Virtual Performance Monitor Unit (vPMU)
>> ===========================================
>>
>> Device types supported:
>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>
>> Instantiate one PMU instance for per VCPU through this API.
>>
>> Groups:
>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>   Attributes:
>>     The attr field of kvm_device_attr encodes two values:
>>     bits:     | 63 .... 32 | 31 .... 0 |
>>     values:   | vcpu_index |  irq_num  |
BTW, I change this Attribute to below format and pass vcpu_index through
this Attribute while pass irq_num through kvm_device_attr.addr.
Is it fine?

    bits:     | 63 .... 32 | 31 ....  0 |
    values:   |  reserved  | vcpu_index |

>>     The irq_num describes the PMU overflow interrupt number for the
>> specified
>>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
>> VM the
>>     interrupt type must be same for each vcpu.
> 
> some formatting snafus that I expect come from pasting the text in an
> e-mail client.
> 
>>
>>   Errors:
>>     -ENXIO: Getting or setting this attribute is not yet supported
> 
> 'not yet supported' as in something we'll implement later, or as in you
> need to call this other function before you can access this state?
> 
Since only when the group is not KVM_DEV_ARM_PMU_GRP_IRQ, it will return
-ENXIO. So what about this?

"-ENXIO: Unsupported attribute group"

Thanks,
-- 
Shannon


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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17  7:22                   ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17  7:22 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/17 4:33, Christoffer Dall wrote:
> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>> Hi,
>>
>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>
>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>
>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>> Documentation clearly describing when this error code is used.
>>>>>
>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>> true per-VCPU property?
>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>> different, so it needs to set them separately. I planned to support both
>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>> users (QEMU) to set these interrupts for each one.
>>
>> How about below vPMU Documentation?
>>
>> ARM Virtual Performance Monitor Unit (vPMU)
>> ===========================================
>>
>> Device types supported:
>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>
>> Instantiate one PMU instance for per VCPU through this API.
>>
>> Groups:
>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>   Attributes:
>>     The attr field of kvm_device_attr encodes two values:
>>     bits:     | 63 .... 32 | 31 .... 0 |
>>     values:   | vcpu_index |  irq_num  |
BTW, I change this Attribute to below format and pass vcpu_index through
this Attribute while pass irq_num through kvm_device_attr.addr.
Is it fine?

    bits:     | 63 .... 32 | 31 ....  0 |
    values:   |  reserved  | vcpu_index |

>>     The irq_num describes the PMU overflow interrupt number for the
>> specified
>>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
>> VM the
>>     interrupt type must be same for each vcpu.
> 
> some formatting snafus that I expect come from pasting the text in an
> e-mail client.
> 
>>
>>   Errors:
>>     -ENXIO: Getting or setting this attribute is not yet supported
> 
> 'not yet supported' as in something we'll implement later, or as in you
> need to call this other function before you can access this state?
> 
Since only when the group is not KVM_DEV_ARM_PMU_GRP_IRQ, it will return
-ENXIO. So what about this?

"-ENXIO: Unsupported attribute group"

Thanks,
-- 
Shannon

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-17  7:22                   ` Shannon Zhao
  (?)
@ 2015-12-17  8:33                     ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17  8:33 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Christoffer Dall, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai

On Thu, 17 Dec 2015 15:22:50 +0800
Shannon Zhao <zhaoshenglong@huawei.com> wrote:

> 
> 
> On 2015/12/17 4:33, Christoffer Dall wrote:
> > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> >> Hi,
> >>
> >> On 2015/12/16 15:31, Shannon Zhao wrote:
> >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
> >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
> >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
> >>>>>>>>>
> >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> >>>>>>>>>
> >>>>> ENXIO or ENODEV would be my choice too, and add that to the
> >>>>> Documentation clearly describing when this error code is used.
> >>>>>
> >>>>> By the way, why do you loop over all VCPUS to set the same value when
> >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
> >>>>> per-VM property (that you can store on the VM data structure) or it's a
> >>>>> true per-VCPU property?
> >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> >>> the interrupt numbers are same for each vcpu, while for SPI they are
> >>> different, so it needs to set them separately. I planned to support both
> >>> PPI and SPI. I think I should add support for SPI at this moment and let
> >>> users (QEMU) to set these interrupts for each one.
> >>
> >> How about below vPMU Documentation?
> >>
> >> ARM Virtual Performance Monitor Unit (vPMU)
> >> ===========================================
> >>
> >> Device types supported:
> >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>
> >> Instantiate one PMU instance for per VCPU through this API.
> >>
> >> Groups:
> >>   KVM_DEV_ARM_PMU_GRP_IRQ
> >>   Attributes:
> >>     The attr field of kvm_device_attr encodes two values:
> >>     bits:     | 63 .... 32 | 31 .... 0 |
> >>     values:   | vcpu_index |  irq_num  |
> BTW, I change this Attribute to below format and pass vcpu_index through
> this Attribute while pass irq_num through kvm_device_attr.addr.
> Is it fine?
> 
>     bits:     | 63 .... 32 | 31 ....  0 |
>     values:   |  reserved  | vcpu_index |

Using the .addr field for something that is clearly not an address is
rather odd. Is there any prior usage of that field for something that
is not an address?

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17  8:33                     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17  8:33 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Christoffer Dall, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai

On Thu, 17 Dec 2015 15:22:50 +0800
Shannon Zhao <zhaoshenglong@huawei.com> wrote:

> 
> 
> On 2015/12/17 4:33, Christoffer Dall wrote:
> > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> >> Hi,
> >>
> >> On 2015/12/16 15:31, Shannon Zhao wrote:
> >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
> >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
> >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
> >>>>>>>>>
> >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> >>>>>>>>>
> >>>>> ENXIO or ENODEV would be my choice too, and add that to the
> >>>>> Documentation clearly describing when this error code is used.
> >>>>>
> >>>>> By the way, why do you loop over all VCPUS to set the same value when
> >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
> >>>>> per-VM property (that you can store on the VM data structure) or it's a
> >>>>> true per-VCPU property?
> >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> >>> the interrupt numbers are same for each vcpu, while for SPI they are
> >>> different, so it needs to set them separately. I planned to support both
> >>> PPI and SPI. I think I should add support for SPI at this moment and let
> >>> users (QEMU) to set these interrupts for each one.
> >>
> >> How about below vPMU Documentation?
> >>
> >> ARM Virtual Performance Monitor Unit (vPMU)
> >> ===========================================
> >>
> >> Device types supported:
> >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>
> >> Instantiate one PMU instance for per VCPU through this API.
> >>
> >> Groups:
> >>   KVM_DEV_ARM_PMU_GRP_IRQ
> >>   Attributes:
> >>     The attr field of kvm_device_attr encodes two values:
> >>     bits:     | 63 .... 32 | 31 .... 0 |
> >>     values:   | vcpu_index |  irq_num  |
> BTW, I change this Attribute to below format and pass vcpu_index through
> this Attribute while pass irq_num through kvm_device_attr.addr.
> Is it fine?
> 
>     bits:     | 63 .... 32 | 31 ....  0 |
>     values:   |  reserved  | vcpu_index |

Using the .addr field for something that is clearly not an address is
rather odd. Is there any prior usage of that field for something that
is not an address?

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17  8:33                     ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17  8:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 17 Dec 2015 15:22:50 +0800
Shannon Zhao <zhaoshenglong@huawei.com> wrote:

> 
> 
> On 2015/12/17 4:33, Christoffer Dall wrote:
> > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> >> Hi,
> >>
> >> On 2015/12/16 15:31, Shannon Zhao wrote:
> >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
> >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
> >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
> >>>>>>>>>
> >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> >>>>>>>>>
> >>>>> ENXIO or ENODEV would be my choice too, and add that to the
> >>>>> Documentation clearly describing when this error code is used.
> >>>>>
> >>>>> By the way, why do you loop over all VCPUS to set the same value when
> >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
> >>>>> per-VM property (that you can store on the VM data structure) or it's a
> >>>>> true per-VCPU property?
> >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> >>> the interrupt numbers are same for each vcpu, while for SPI they are
> >>> different, so it needs to set them separately. I planned to support both
> >>> PPI and SPI. I think I should add support for SPI at this moment and let
> >>> users (QEMU) to set these interrupts for each one.
> >>
> >> How about below vPMU Documentation?
> >>
> >> ARM Virtual Performance Monitor Unit (vPMU)
> >> ===========================================
> >>
> >> Device types supported:
> >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>
> >> Instantiate one PMU instance for per VCPU through this API.
> >>
> >> Groups:
> >>   KVM_DEV_ARM_PMU_GRP_IRQ
> >>   Attributes:
> >>     The attr field of kvm_device_attr encodes two values:
> >>     bits:     | 63 .... 32 | 31 .... 0 |
> >>     values:   | vcpu_index |  irq_num  |
> BTW, I change this Attribute to below format and pass vcpu_index through
> this Attribute while pass irq_num through kvm_device_attr.addr.
> Is it fine?
> 
>     bits:     | 63 .... 32 | 31 ....  0 |
>     values:   |  reserved  | vcpu_index |

Using the .addr field for something that is clearly not an address is
rather odd. Is there any prior usage of that field for something that
is not an address?

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-17  8:33                     ` Marc Zyngier
  (?)
@ 2015-12-17  8:41                       ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17  8:41 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/17 16:33, Marc Zyngier wrote:
> On Thu, 17 Dec 2015 15:22:50 +0800
> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
> 
>> > 
>> > 
>> > On 2015/12/17 4:33, Christoffer Dall wrote:
>>> > > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>> > >> Hi,
>>>> > >>
>>>> > >> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>> > >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>> > >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>> > >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>> > >>>>>>>>>
>>>>>>>>>>> > >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>> > >>>>>>>>>
>>>>>>> > >>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>> > >>>>> Documentation clearly describing when this error code is used.
>>>>>>> > >>>>>
>>>>>>> > >>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>> > >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>> > >>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>> > >>>>> true per-VCPU property?
>>>>> > >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>> > >>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>> > >>> different, so it needs to set them separately. I planned to support both
>>>>> > >>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>> > >>> users (QEMU) to set these interrupts for each one.
>>>> > >>
>>>> > >> How about below vPMU Documentation?
>>>> > >>
>>>> > >> ARM Virtual Performance Monitor Unit (vPMU)
>>>> > >> ===========================================
>>>> > >>
>>>> > >> Device types supported:
>>>> > >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>> > >>
>>>> > >> Instantiate one PMU instance for per VCPU through this API.
>>>> > >>
>>>> > >> Groups:
>>>> > >>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>> > >>   Attributes:
>>>> > >>     The attr field of kvm_device_attr encodes two values:
>>>> > >>     bits:     | 63 .... 32 | 31 .... 0 |
>>>> > >>     values:   | vcpu_index |  irq_num  |
>> > BTW, I change this Attribute to below format and pass vcpu_index through
>> > this Attribute while pass irq_num through kvm_device_attr.addr.
>> > Is it fine?
>> > 
>> >     bits:     | 63 .... 32 | 31 ....  0 |
>> >     values:   |  reserved  | vcpu_index |
> Using the .addr field for something that is clearly not an address is
> rather odd. Is there any prior usage of that field for something that
> is not an address?

I see this usage in vgic_attr_regs_access(). But if you prefer previous
one, I'll use that.

-- 
Shannon


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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17  8:41                       ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17  8:41 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/17 16:33, Marc Zyngier wrote:
> On Thu, 17 Dec 2015 15:22:50 +0800
> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
> 
>> > 
>> > 
>> > On 2015/12/17 4:33, Christoffer Dall wrote:
>>> > > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>> > >> Hi,
>>>> > >>
>>>> > >> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>> > >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>> > >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>> > >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>> > >>>>>>>>>
>>>>>>>>>>> > >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>> > >>>>>>>>>
>>>>>>> > >>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>> > >>>>> Documentation clearly describing when this error code is used.
>>>>>>> > >>>>>
>>>>>>> > >>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>> > >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>> > >>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>> > >>>>> true per-VCPU property?
>>>>> > >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>> > >>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>> > >>> different, so it needs to set them separately. I planned to support both
>>>>> > >>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>> > >>> users (QEMU) to set these interrupts for each one.
>>>> > >>
>>>> > >> How about below vPMU Documentation?
>>>> > >>
>>>> > >> ARM Virtual Performance Monitor Unit (vPMU)
>>>> > >> ===========================================
>>>> > >>
>>>> > >> Device types supported:
>>>> > >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>> > >>
>>>> > >> Instantiate one PMU instance for per VCPU through this API.
>>>> > >>
>>>> > >> Groups:
>>>> > >>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>> > >>   Attributes:
>>>> > >>     The attr field of kvm_device_attr encodes two values:
>>>> > >>     bits:     | 63 .... 32 | 31 .... 0 |
>>>> > >>     values:   | vcpu_index |  irq_num  |
>> > BTW, I change this Attribute to below format and pass vcpu_index through
>> > this Attribute while pass irq_num through kvm_device_attr.addr.
>> > Is it fine?
>> > 
>> >     bits:     | 63 .... 32 | 31 ....  0 |
>> >     values:   |  reserved  | vcpu_index |
> Using the .addr field for something that is clearly not an address is
> rather odd. Is there any prior usage of that field for something that
> is not an address?

I see this usage in vgic_attr_regs_access(). But if you prefer previous
one, I'll use that.

-- 
Shannon


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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17  8:41                       ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17  8:41 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/17 16:33, Marc Zyngier wrote:
> On Thu, 17 Dec 2015 15:22:50 +0800
> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
> 
>> > 
>> > 
>> > On 2015/12/17 4:33, Christoffer Dall wrote:
>>> > > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>> > >> Hi,
>>>> > >>
>>>> > >> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>> > >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>> > >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>> > >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>> > >>>>>>>>>
>>>>>>>>>>> > >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>> > >>>>>>>>>
>>>>>>> > >>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>> > >>>>> Documentation clearly describing when this error code is used.
>>>>>>> > >>>>>
>>>>>>> > >>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>> > >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>> > >>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>> > >>>>> true per-VCPU property?
>>>>> > >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>> > >>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>> > >>> different, so it needs to set them separately. I planned to support both
>>>>> > >>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>> > >>> users (QEMU) to set these interrupts for each one.
>>>> > >>
>>>> > >> How about below vPMU Documentation?
>>>> > >>
>>>> > >> ARM Virtual Performance Monitor Unit (vPMU)
>>>> > >> ===========================================
>>>> > >>
>>>> > >> Device types supported:
>>>> > >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>> > >>
>>>> > >> Instantiate one PMU instance for per VCPU through this API.
>>>> > >>
>>>> > >> Groups:
>>>> > >>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>> > >>   Attributes:
>>>> > >>     The attr field of kvm_device_attr encodes two values:
>>>> > >>     bits:     | 63 .... 32 | 31 .... 0 |
>>>> > >>     values:   | vcpu_index |  irq_num  |
>> > BTW, I change this Attribute to below format and pass vcpu_index through
>> > this Attribute while pass irq_num through kvm_device_attr.addr.
>> > Is it fine?
>> > 
>> >     bits:     | 63 .... 32 | 31 ....  0 |
>> >     values:   |  reserved  | vcpu_index |
> Using the .addr field for something that is clearly not an address is
> rather odd. Is there any prior usage of that field for something that
> is not an address?

I see this usage in vgic_attr_regs_access(). But if you prefer previous
one, I'll use that.

-- 
Shannon

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-17  8:41                       ` Shannon Zhao
@ 2015-12-17  9:38                         ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17  9:38 UTC (permalink / raw)
  To: Shannon Zhao, Christoffer Dall
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai

On 17/12/15 08:41, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 16:33, Marc Zyngier wrote:
>> On Thu, 17 Dec 2015 15:22:50 +0800
>> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>
>>>>
>>>>
>>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>> different, so it needs to set them separately. I planned to support both
>>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>
>>>>>>>> How about below vPMU Documentation?
>>>>>>>>
>>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>> ===========================================
>>>>>>>>
>>>>>>>> Device types supported:
>>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>>>>
>>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>
>>>>>>>> Groups:
>>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>   Attributes:
>>>>>>>>     The attr field of kvm_device_attr encodes two values:
>>>>>>>>     bits:     | 63 .... 32 | 31 .... 0 |
>>>>>>>>     values:   | vcpu_index |  irq_num  |
>>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>> Is it fine?
>>>>
>>>>     bits:     | 63 .... 32 | 31 ....  0 |
>>>>     values:   |  reserved  | vcpu_index |
>> Using the .addr field for something that is clearly not an address is
>> rather odd. Is there any prior usage of that field for something that
>> is not an address?
> 
> I see this usage in vgic_attr_regs_access(). But if you prefer previous
> one, I'll use that.

Ah, you're using the .addr field to point to a userspace value, not to
carry the value itself! That'd be fine by me (even if I still prefer the
original one), but I'd like others to chime in (I'm quite bad at
defining userspace stuff...).

Thanks,

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

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17  9:38                         ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

On 17/12/15 08:41, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 16:33, Marc Zyngier wrote:
>> On Thu, 17 Dec 2015 15:22:50 +0800
>> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>
>>>>
>>>>
>>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>> different, so it needs to set them separately. I planned to support both
>>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>
>>>>>>>> How about below vPMU Documentation?
>>>>>>>>
>>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>> ===========================================
>>>>>>>>
>>>>>>>> Device types supported:
>>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>>>>
>>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>
>>>>>>>> Groups:
>>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>   Attributes:
>>>>>>>>     The attr field of kvm_device_attr encodes two values:
>>>>>>>>     bits:     | 63 .... 32 | 31 .... 0 |
>>>>>>>>     values:   | vcpu_index |  irq_num  |
>>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>> Is it fine?
>>>>
>>>>     bits:     | 63 .... 32 | 31 ....  0 |
>>>>     values:   |  reserved  | vcpu_index |
>> Using the .addr field for something that is clearly not an address is
>> rather odd. Is there any prior usage of that field for something that
>> is not an address?
> 
> I see this usage in vgic_attr_regs_access(). But if you prefer previous
> one, I'll use that.

Ah, you're using the .addr field to point to a userspace value, not to
carry the value itself! That'd be fine by me (even if I still prefer the
original one), but I'd like others to chime in (I'm quite bad at
defining userspace stuff...).

Thanks,

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

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-17  9:38                         ` Marc Zyngier
  (?)
@ 2015-12-17 10:10                           ` Shannon Zhao
  -1 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17 10:10 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/17 17:38, Marc Zyngier wrote:
> On 17/12/15 08:41, Shannon Zhao wrote:
>> > 
>> > 
>> > On 2015/12/17 16:33, Marc Zyngier wrote:
>>> >> On Thu, 17 Dec 2015 15:22:50 +0800
>>> >> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>> >>
>>>>> >>>>
>>>>> >>>>
>>>>> >>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>>> >>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>>> >>>>>>>> Hi,
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>> >>>>>>>>>>>>>>
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>>> >>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>>>>>>>> >>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>>> >>>>>>>>>> different, so it needs to set them separately. I planned to support both
>>>>>>>>>>> >>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>>>>>>>> >>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> How about below vPMU Documentation?
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>>> >>>>>>>> ===========================================
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Device types supported:
>>>>>>>>> >>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Groups:
>>>>>>>>> >>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>> >>>>>>>>   Attributes:
>>>>>>>>> >>>>>>>>     The attr field of kvm_device_attr encodes two values:
>>>>>>>>> >>>>>>>>     bits:     | 63 .... 32 | 31 .... 0 |
>>>>>>>>> >>>>>>>>     values:   | vcpu_index |  irq_num  |
>>>>> >>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>>> >>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>>> >>>> Is it fine?
>>>>> >>>>
>>>>> >>>>     bits:     | 63 .... 32 | 31 ....  0 |
>>>>> >>>>     values:   |  reserved  | vcpu_index |
>>> >> Using the .addr field for something that is clearly not an address is
>>> >> rather odd. Is there any prior usage of that field for something that
>>> >> is not an address?
>> > 
>> > I see this usage in vgic_attr_regs_access(). But if you prefer previous
>> > one, I'll use that.
> Ah, you're using the .addr field to point to a userspace value, not to
> carry the value itself! That'd be fine by me (even if I still prefer the
> original one), but I'd like others to chime in (I'm quite bad at
> defining userspace stuff...).

Another reason I think is that it needs to pass the irq_num to user
space when calling get_attr. It could be passed via kvm_device_attr.addr
while can't be passed via kvm_device_attr.attr within current framework.

Thanks,
-- 
Shannon


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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17 10:10                           ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17 10:10 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai



On 2015/12/17 17:38, Marc Zyngier wrote:
> On 17/12/15 08:41, Shannon Zhao wrote:
>> > 
>> > 
>> > On 2015/12/17 16:33, Marc Zyngier wrote:
>>> >> On Thu, 17 Dec 2015 15:22:50 +0800
>>> >> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>> >>
>>>>> >>>>
>>>>> >>>>
>>>>> >>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>>> >>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>>> >>>>>>>> Hi,
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>> >>>>>>>>>>>>>>
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>>> >>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>>>>>>>> >>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>>> >>>>>>>>>> different, so it needs to set them separately. I planned to support both
>>>>>>>>>>> >>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>>>>>>>> >>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> How about below vPMU Documentation?
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>>> >>>>>>>> ===========================================
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Device types supported:
>>>>>>>>> >>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Groups:
>>>>>>>>> >>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>> >>>>>>>>   Attributes:
>>>>>>>>> >>>>>>>>     The attr field of kvm_device_attr encodes two values:
>>>>>>>>> >>>>>>>>     bits:     | 63 .... 32 | 31 .... 0 |
>>>>>>>>> >>>>>>>>     values:   | vcpu_index |  irq_num  |
>>>>> >>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>>> >>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>>> >>>> Is it fine?
>>>>> >>>>
>>>>> >>>>     bits:     | 63 .... 32 | 31 ....  0 |
>>>>> >>>>     values:   |  reserved  | vcpu_index |
>>> >> Using the .addr field for something that is clearly not an address is
>>> >> rather odd. Is there any prior usage of that field for something that
>>> >> is not an address?
>> > 
>> > I see this usage in vgic_attr_regs_access(). But if you prefer previous
>> > one, I'll use that.
> Ah, you're using the .addr field to point to a userspace value, not to
> carry the value itself! That'd be fine by me (even if I still prefer the
> original one), but I'd like others to chime in (I'm quite bad at
> defining userspace stuff...).

Another reason I think is that it needs to pass the irq_num to user
space when calling get_attr. It could be passed via kvm_device_attr.addr
while can't be passed via kvm_device_attr.attr within current framework.

Thanks,
-- 
Shannon


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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17 10:10                           ` Shannon Zhao
  0 siblings, 0 replies; 135+ messages in thread
From: Shannon Zhao @ 2015-12-17 10:10 UTC (permalink / raw)
  To: linux-arm-kernel



On 2015/12/17 17:38, Marc Zyngier wrote:
> On 17/12/15 08:41, Shannon Zhao wrote:
>> > 
>> > 
>> > On 2015/12/17 16:33, Marc Zyngier wrote:
>>> >> On Thu, 17 Dec 2015 15:22:50 +0800
>>> >> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>> >>
>>>>> >>>>
>>>>> >>>>
>>>>> >>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>>> >>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>>> >>>>>>>> Hi,
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>> >>>>>>>>>>>>>>
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>>>>>>>>>> >>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>>> >>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>>>>>>>> >>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>>> >>>>>>>>>> different, so it needs to set them separately. I planned to support both
>>>>>>>>>>> >>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>>>>>>>> >>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> How about below vPMU Documentation?
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>>> >>>>>>>> ===========================================
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Device types supported:
>>>>>>>>> >>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>> >>>>>>>>
>>>>>>>>> >>>>>>>> Groups:
>>>>>>>>> >>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>> >>>>>>>>   Attributes:
>>>>>>>>> >>>>>>>>     The attr field of kvm_device_attr encodes two values:
>>>>>>>>> >>>>>>>>     bits:     | 63 .... 32 | 31 .... 0 |
>>>>>>>>> >>>>>>>>     values:   | vcpu_index |  irq_num  |
>>>>> >>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>>> >>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>>> >>>> Is it fine?
>>>>> >>>>
>>>>> >>>>     bits:     | 63 .... 32 | 31 ....  0 |
>>>>> >>>>     values:   |  reserved  | vcpu_index |
>>> >> Using the .addr field for something that is clearly not an address is
>>> >> rather odd. Is there any prior usage of that field for something that
>>> >> is not an address?
>> > 
>> > I see this usage in vgic_attr_regs_access(). But if you prefer previous
>> > one, I'll use that.
> Ah, you're using the .addr field to point to a userspace value, not to
> carry the value itself! That'd be fine by me (even if I still prefer the
> original one), but I'd like others to chime in (I'm quite bad at
> defining userspace stuff...).

Another reason I think is that it needs to pass the irq_num to user
space when calling get_attr. It could be passed via kvm_device_attr.addr
while can't be passed via kvm_device_attr.attr within current framework.

Thanks,
-- 
Shannon

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-17 10:10                           ` Shannon Zhao
@ 2015-12-17 10:38                             ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17 10:38 UTC (permalink / raw)
  To: Shannon Zhao, Christoffer Dall
  Cc: Shannon Zhao, kvmarm, linux-arm-kernel, kvm, will.deacon,
	alex.bennee, wei, cov, peter.huangpeng, hangaohuai

On 17/12/15 10:10, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 17:38, Marc Zyngier wrote:
>> On 17/12/15 08:41, Shannon Zhao wrote:
>>>>
>>>>
>>>> On 2015/12/17 16:33, Marc Zyngier wrote:
>>>>>> On Thu, 17 Dec 2015 15:22:50 +0800
>>>>>> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>>>>>>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>>>>>>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>>>>>>>>>>>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>>>>>>>>>>>>>> different, so it needs to set them separately. I planned to support both
>>>>>>>>>>>>>>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>>>>>>>>>>>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> How about below vPMU Documentation?
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>>>>>>>>>>>> ===========================================
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Device types supported:
>>>>>>>>>>>>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Groups:
>>>>>>>>>>>>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>>>>>>>>>>>   Attributes:
>>>>>>>>>>>>>>>>>>     The attr field of kvm_device_attr encodes two values:
>>>>>>>>>>>>>>>>>>     bits:     | 63 .... 32 | 31 .... 0 |
>>>>>>>>>>>>>>>>>>     values:   | vcpu_index |  irq_num  |
>>>>>>>>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>>>>>>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>>>>>>>> Is it fine?
>>>>>>>>>>
>>>>>>>>>>     bits:     | 63 .... 32 | 31 ....  0 |
>>>>>>>>>>     values:   |  reserved  | vcpu_index |
>>>>>> Using the .addr field for something that is clearly not an address is
>>>>>> rather odd. Is there any prior usage of that field for something that
>>>>>> is not an address?
>>>>
>>>> I see this usage in vgic_attr_regs_access(). But if you prefer previous
>>>> one, I'll use that.
>> Ah, you're using the .addr field to point to a userspace value, not to
>> carry the value itself! That'd be fine by me (even if I still prefer the
>> original one), but I'd like others to chime in (I'm quite bad at
>> defining userspace stuff...).
> 
> Another reason I think is that it needs to pass the irq_num to user
> space when calling get_attr. It could be passed via kvm_device_attr.addr
> while can't be passed via kvm_device_attr.attr within current framework.

That's a very good reason. Go for it.

Thanks,

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

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-17 10:38                             ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

On 17/12/15 10:10, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 17:38, Marc Zyngier wrote:
>> On 17/12/15 08:41, Shannon Zhao wrote:
>>>>
>>>>
>>>> On 2015/12/17 16:33, Marc Zyngier wrote:
>>>>>> On Thu, 17 Dec 2015 15:22:50 +0800
>>>>>> Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 2015/12/17 4:33, Christoffer Dall wrote:
>>>>>>>>>>>>>> On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> On 2015/12/16 15:31, Shannon Zhao wrote:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ENXIO or ENODEV would be my choice too, and add that to the
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Documentation clearly describing when this error code is used.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> By the way, why do you loop over all VCPUS to set the same value when
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> per-VM property (that you can store on the VM data structure) or it's a
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> true per-VCPU property?
>>>>>>>>>>>>>>>>>>>>>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
>>>>>>>>>>>>>>>>>>>>>> the interrupt numbers are same for each vcpu, while for SPI they are
>>>>>>>>>>>>>>>>>>>>>> different, so it needs to set them separately. I planned to support both
>>>>>>>>>>>>>>>>>>>>>> PPI and SPI. I think I should add support for SPI at this moment and let
>>>>>>>>>>>>>>>>>>>>>> users (QEMU) to set these interrupts for each one.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> How about below vPMU Documentation?
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> ARM Virtual Performance Monitor Unit (vPMU)
>>>>>>>>>>>>>>>>>> ===========================================
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Device types supported:
>>>>>>>>>>>>>>>>>>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Instantiate one PMU instance for per VCPU through this API.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Groups:
>>>>>>>>>>>>>>>>>>   KVM_DEV_ARM_PMU_GRP_IRQ
>>>>>>>>>>>>>>>>>>   Attributes:
>>>>>>>>>>>>>>>>>>     The attr field of kvm_device_attr encodes two values:
>>>>>>>>>>>>>>>>>>     bits:     | 63 .... 32 | 31 .... 0 |
>>>>>>>>>>>>>>>>>>     values:   | vcpu_index |  irq_num  |
>>>>>>>>>> BTW, I change this Attribute to below format and pass vcpu_index through
>>>>>>>>>> this Attribute while pass irq_num through kvm_device_attr.addr.
>>>>>>>>>> Is it fine?
>>>>>>>>>>
>>>>>>>>>>     bits:     | 63 .... 32 | 31 ....  0 |
>>>>>>>>>>     values:   |  reserved  | vcpu_index |
>>>>>> Using the .addr field for something that is clearly not an address is
>>>>>> rather odd. Is there any prior usage of that field for something that
>>>>>> is not an address?
>>>>
>>>> I see this usage in vgic_attr_regs_access(). But if you prefer previous
>>>> one, I'll use that.
>> Ah, you're using the .addr field to point to a userspace value, not to
>> carry the value itself! That'd be fine by me (even if I still prefer the
>> original one), but I'd like others to chime in (I'm quite bad at
>> defining userspace stuff...).
> 
> Another reason I think is that it needs to pass the irq_num to user
> space when calling get_attr. It could be passed via kvm_device_attr.addr
> while can't be passed via kvm_device_attr.attr within current framework.

That's a very good reason. Go for it.

Thanks,

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

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

* Re: [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function
  2015-12-15  8:49   ` Shannon Zhao
@ 2015-12-17 15:22     ` Mark Rutland
  -1 siblings, 0 replies; 135+ messages in thread
From: Mark Rutland @ 2015-12-17 15:22 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: kvmarm, marc.zyngier, christoffer.dall, kvm, will.deacon,
	linux-arm-kernel, shannon.zhao

On Tue, Dec 15, 2015 at 04:49:27PM +0800, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> When we use tools like perf on host, perf passes the event type and the
> id of this event type category to kernel, then kernel will map them to
> hardware event number and write this number to PMU PMEVTYPER<n>_EL0
> register. When getting the event number in KVM, directly use raw event
> type to create a perf_event for it.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/include/asm/pmu.h |   3 ++
>  arch/arm64/kvm/Makefile      |   1 +
>  include/kvm/arm_pmu.h        |  11 ++++
>  virt/kvm/arm/pmu.c           | 122 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 137 insertions(+)
>  create mode 100644 virt/kvm/arm/pmu.c

[...]

> +/**
> + * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
> + * @vcpu: The vcpu pointer
> + * @data: The data guest writes to PMXEVTYPER_EL0
> + * @select_idx: The number of selected counter
> + *
> + * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
> + * event with given hardware event number. Here we call perf_event API to
> + * emulate this action and create a kernel perf event for it.
> + */
> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> +				    u64 select_idx)
> +{
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
> +	struct perf_event *event;
> +	struct perf_event_attr attr;
> +	u64 eventsel, counter;
> +
> +	kvm_pmu_stop_counter(vcpu, pmc);
> +	eventsel = data & ARMV8_EVTYPE_EVENT;
> +
> +	memset(&attr, 0, sizeof(struct perf_event_attr));
> +	attr.type = PERF_TYPE_RAW;
> +	attr.size = sizeof(attr);
> +	attr.pinned = 1;
> +	attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
> +	attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
> +	attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
> +	attr.exclude_hv = 1; /* Don't count EL2 events */
> +	attr.exclude_host = 1; /* Don't count host events */
> +	attr.config = eventsel;
> +
> +	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
> +	/* The initial sample period (overflow count) of an event. */
> +	attr.sample_period = (-counter) & pmc->bitmask;
> +
> +	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);

As far as I can see, this is going to result in unreliable counts on a
big.LITTLE system, even if the VCPUs are constrained to one class of
core.

As this is a task-bound event (cpu == -1, task is current), the perf
core will stop as soon as one PMU driver agrees to handle the event. The
event will then only count on CPUs handled by that driver.

If you're unlucky, the set of CPUs handled by that driver is not the
same as the set of CPUs your VM is constrained to. e.g. your VM might be
on little cores, but the big PMU driver accepted the event, and only
counts on big cores.

I'm not sure how we can solve that.

Thanks,
Mark.

> +	if (IS_ERR(event)) {
> +		printk_once("kvm: pmu event creation failed %ld\n",
> +			    PTR_ERR(event));
> +		return;
> +	}
> +
> +	pmc->perf_event = event;
> +}
> -- 
> 2.0.4
> 
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 

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

* [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function
@ 2015-12-17 15:22     ` Mark Rutland
  0 siblings, 0 replies; 135+ messages in thread
From: Mark Rutland @ 2015-12-17 15:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 15, 2015 at 04:49:27PM +0800, Shannon Zhao wrote:
> From: Shannon Zhao <shannon.zhao@linaro.org>
> 
> When we use tools like perf on host, perf passes the event type and the
> id of this event type category to kernel, then kernel will map them to
> hardware event number and write this number to PMU PMEVTYPER<n>_EL0
> register. When getting the event number in KVM, directly use raw event
> type to create a perf_event for it.
> 
> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
> ---
>  arch/arm64/include/asm/pmu.h |   3 ++
>  arch/arm64/kvm/Makefile      |   1 +
>  include/kvm/arm_pmu.h        |  11 ++++
>  virt/kvm/arm/pmu.c           | 122 +++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 137 insertions(+)
>  create mode 100644 virt/kvm/arm/pmu.c

[...]

> +/**
> + * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
> + * @vcpu: The vcpu pointer
> + * @data: The data guest writes to PMXEVTYPER_EL0
> + * @select_idx: The number of selected counter
> + *
> + * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
> + * event with given hardware event number. Here we call perf_event API to
> + * emulate this action and create a kernel perf event for it.
> + */
> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
> +				    u64 select_idx)
> +{
> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
> +	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
> +	struct perf_event *event;
> +	struct perf_event_attr attr;
> +	u64 eventsel, counter;
> +
> +	kvm_pmu_stop_counter(vcpu, pmc);
> +	eventsel = data & ARMV8_EVTYPE_EVENT;
> +
> +	memset(&attr, 0, sizeof(struct perf_event_attr));
> +	attr.type = PERF_TYPE_RAW;
> +	attr.size = sizeof(attr);
> +	attr.pinned = 1;
> +	attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
> +	attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
> +	attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
> +	attr.exclude_hv = 1; /* Don't count EL2 events */
> +	attr.exclude_host = 1; /* Don't count host events */
> +	attr.config = eventsel;
> +
> +	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
> +	/* The initial sample period (overflow count) of an event. */
> +	attr.sample_period = (-counter) & pmc->bitmask;
> +
> +	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);

As far as I can see, this is going to result in unreliable counts on a
big.LITTLE system, even if the VCPUs are constrained to one class of
core.

As this is a task-bound event (cpu == -1, task is current), the perf
core will stop as soon as one PMU driver agrees to handle the event. The
event will then only count on CPUs handled by that driver.

If you're unlucky, the set of CPUs handled by that driver is not the
same as the set of CPUs your VM is constrained to. e.g. your VM might be
on little cores, but the big PMU driver accepted the event, and only
counts on big cores.

I'm not sure how we can solve that.

Thanks,
Mark.

> +	if (IS_ERR(event)) {
> +		printk_once("kvm: pmu event creation failed %ld\n",
> +			    PTR_ERR(event));
> +		return;
> +	}
> +
> +	pmc->perf_event = event;
> +}
> -- 
> 2.0.4
> 
> 
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
> 

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

* Re: [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function
  2015-12-17 15:22     ` Mark Rutland
@ 2015-12-17 15:30       ` Marc Zyngier
  -1 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17 15:30 UTC (permalink / raw)
  To: Mark Rutland, Shannon Zhao
  Cc: kvmarm, christoffer.dall, kvm, will.deacon, linux-arm-kernel,
	shannon.zhao

On 17/12/15 15:22, Mark Rutland wrote:
> On Tue, Dec 15, 2015 at 04:49:27PM +0800, Shannon Zhao wrote:
>> From: Shannon Zhao <shannon.zhao@linaro.org>
>>
>> When we use tools like perf on host, perf passes the event type and the
>> id of this event type category to kernel, then kernel will map them to
>> hardware event number and write this number to PMU PMEVTYPER<n>_EL0
>> register. When getting the event number in KVM, directly use raw event
>> type to create a perf_event for it.
>>
>> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
>> ---
>>  arch/arm64/include/asm/pmu.h |   3 ++
>>  arch/arm64/kvm/Makefile      |   1 +
>>  include/kvm/arm_pmu.h        |  11 ++++
>>  virt/kvm/arm/pmu.c           | 122 +++++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 137 insertions(+)
>>  create mode 100644 virt/kvm/arm/pmu.c
> 
> [...]
> 
>> +/**
>> + * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>> + * @vcpu: The vcpu pointer
>> + * @data: The data guest writes to PMXEVTYPER_EL0
>> + * @select_idx: The number of selected counter
>> + *
>> + * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
>> + * event with given hardware event number. Here we call perf_event API to
>> + * emulate this action and create a kernel perf event for it.
>> + */
>> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>> +				    u64 select_idx)
>> +{
>> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
>> +	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
>> +	struct perf_event *event;
>> +	struct perf_event_attr attr;
>> +	u64 eventsel, counter;
>> +
>> +	kvm_pmu_stop_counter(vcpu, pmc);
>> +	eventsel = data & ARMV8_EVTYPE_EVENT;
>> +
>> +	memset(&attr, 0, sizeof(struct perf_event_attr));
>> +	attr.type = PERF_TYPE_RAW;
>> +	attr.size = sizeof(attr);
>> +	attr.pinned = 1;
>> +	attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
>> +	attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
>> +	attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
>> +	attr.exclude_hv = 1; /* Don't count EL2 events */
>> +	attr.exclude_host = 1; /* Don't count host events */
>> +	attr.config = eventsel;
>> +
>> +	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
>> +	/* The initial sample period (overflow count) of an event. */
>> +	attr.sample_period = (-counter) & pmc->bitmask;
>> +
>> +	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
> 
> As far as I can see, this is going to result in unreliable counts on a
> big.LITTLE system, even if the VCPUs are constrained to one class of
> core.
> 
> As this is a task-bound event (cpu == -1, task is current), the perf
> core will stop as soon as one PMU driver agrees to handle the event. The
> event will then only count on CPUs handled by that driver.
> 
> If you're unlucky, the set of CPUs handled by that driver is not the
> same as the set of CPUs your VM is constrained to. e.g. your VM might be
> on little cores, but the big PMU driver accepted the event, and only
> counts on big cores.
> 
> I'm not sure how we can solve that.

Yeah, another level of BL braindeadness. We should have some API to
match the PMU we want on the CPU we're on at the moment that trap occurs.

I don't think this should block this series though - this is something
we can improve on in parallel (a possible solution being to forbid KVM
on BL platform altogether).

Thanks,

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

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

* [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function
@ 2015-12-17 15:30       ` Marc Zyngier
  0 siblings, 0 replies; 135+ messages in thread
From: Marc Zyngier @ 2015-12-17 15:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 17/12/15 15:22, Mark Rutland wrote:
> On Tue, Dec 15, 2015 at 04:49:27PM +0800, Shannon Zhao wrote:
>> From: Shannon Zhao <shannon.zhao@linaro.org>
>>
>> When we use tools like perf on host, perf passes the event type and the
>> id of this event type category to kernel, then kernel will map them to
>> hardware event number and write this number to PMU PMEVTYPER<n>_EL0
>> register. When getting the event number in KVM, directly use raw event
>> type to create a perf_event for it.
>>
>> Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
>> ---
>>  arch/arm64/include/asm/pmu.h |   3 ++
>>  arch/arm64/kvm/Makefile      |   1 +
>>  include/kvm/arm_pmu.h        |  11 ++++
>>  virt/kvm/arm/pmu.c           | 122 +++++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 137 insertions(+)
>>  create mode 100644 virt/kvm/arm/pmu.c
> 
> [...]
> 
>> +/**
>> + * kvm_pmu_set_counter_event_type - set selected counter to monitor some event
>> + * @vcpu: The vcpu pointer
>> + * @data: The data guest writes to PMXEVTYPER_EL0
>> + * @select_idx: The number of selected counter
>> + *
>> + * When OS accesses PMXEVTYPER_EL0, that means it wants to set a PMC to count an
>> + * event with given hardware event number. Here we call perf_event API to
>> + * emulate this action and create a kernel perf event for it.
>> + */
>> +void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
>> +				    u64 select_idx)
>> +{
>> +	struct kvm_pmu *pmu = &vcpu->arch.pmu;
>> +	struct kvm_pmc *pmc = &pmu->pmc[select_idx];
>> +	struct perf_event *event;
>> +	struct perf_event_attr attr;
>> +	u64 eventsel, counter;
>> +
>> +	kvm_pmu_stop_counter(vcpu, pmc);
>> +	eventsel = data & ARMV8_EVTYPE_EVENT;
>> +
>> +	memset(&attr, 0, sizeof(struct perf_event_attr));
>> +	attr.type = PERF_TYPE_RAW;
>> +	attr.size = sizeof(attr);
>> +	attr.pinned = 1;
>> +	attr.disabled = kvm_pmu_counter_is_enabled(vcpu, select_idx);
>> +	attr.exclude_user = data & ARMV8_EXCLUDE_EL0 ? 1 : 0;
>> +	attr.exclude_kernel = data & ARMV8_EXCLUDE_EL1 ? 1 : 0;
>> +	attr.exclude_hv = 1; /* Don't count EL2 events */
>> +	attr.exclude_host = 1; /* Don't count host events */
>> +	attr.config = eventsel;
>> +
>> +	counter = kvm_pmu_get_counter_value(vcpu, select_idx);
>> +	/* The initial sample period (overflow count) of an event. */
>> +	attr.sample_period = (-counter) & pmc->bitmask;
>> +
>> +	event = perf_event_create_kernel_counter(&attr, -1, current, NULL, pmc);
> 
> As far as I can see, this is going to result in unreliable counts on a
> big.LITTLE system, even if the VCPUs are constrained to one class of
> core.
> 
> As this is a task-bound event (cpu == -1, task is current), the perf
> core will stop as soon as one PMU driver agrees to handle the event. The
> event will then only count on CPUs handled by that driver.
> 
> If you're unlucky, the set of CPUs handled by that driver is not the
> same as the set of CPUs your VM is constrained to. e.g. your VM might be
> on little cores, but the big PMU driver accepted the event, and only
> counts on big cores.
> 
> I'm not sure how we can solve that.

Yeah, another level of BL braindeadness. We should have some API to
match the PMU we want on the CPU we're on at the moment that trap occurs.

I don't think this should block this series though - this is something
we can improve on in parallel (a possible solution being to forbid KVM
on BL platform altogether).

Thanks,

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

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

* Re: [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
  2015-12-17  7:22                   ` Shannon Zhao
@ 2015-12-18 10:00                     ` Christoffer Dall
  -1 siblings, 0 replies; 135+ messages in thread
From: Christoffer Dall @ 2015-12-18 10:00 UTC (permalink / raw)
  To: Shannon Zhao
  Cc: Marc Zyngier, Shannon Zhao, kvmarm, linux-arm-kernel, kvm,
	will.deacon, alex.bennee, wei, cov, peter.huangpeng, hangaohuai

On Thu, Dec 17, 2015 at 03:22:50PM +0800, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 4:33, Christoffer Dall wrote:
> > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> >> Hi,
> >>
> >> On 2015/12/16 15:31, Shannon Zhao wrote:
> >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
> >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
> >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
> >>>>>>>>>
> >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> >>>>>>>>>
> >>>>> ENXIO or ENODEV would be my choice too, and add that to the
> >>>>> Documentation clearly describing when this error code is used.
> >>>>>
> >>>>> By the way, why do you loop over all VCPUS to set the same value when
> >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
> >>>>> per-VM property (that you can store on the VM data structure) or it's a
> >>>>> true per-VCPU property?
> >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> >>> the interrupt numbers are same for each vcpu, while for SPI they are
> >>> different, so it needs to set them separately. I planned to support both
> >>> PPI and SPI. I think I should add support for SPI at this moment and let
> >>> users (QEMU) to set these interrupts for each one.
> >>
> >> How about below vPMU Documentation?
> >>
> >> ARM Virtual Performance Monitor Unit (vPMU)
> >> ===========================================
> >>
> >> Device types supported:
> >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>
> >> Instantiate one PMU instance for per VCPU through this API.
> >>
> >> Groups:
> >>   KVM_DEV_ARM_PMU_GRP_IRQ
> >>   Attributes:
> >>     The attr field of kvm_device_attr encodes two values:
> >>     bits:     | 63 .... 32 | 31 .... 0 |
> >>     values:   | vcpu_index |  irq_num  |
> BTW, I change this Attribute to below format and pass vcpu_index through
> this Attribute while pass irq_num through kvm_device_attr.addr.
> Is it fine?
> 
>     bits:     | 63 .... 32 | 31 ....  0 |
>     values:   |  reserved  | vcpu_index |
> 
> >>     The irq_num describes the PMU overflow interrupt number for the
> >> specified
> >>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
> >> VM the
> >>     interrupt type must be same for each vcpu.
> > 
> > some formatting snafus that I expect come from pasting the text in an
> > e-mail client.
> > 
> >>
> >>   Errors:
> >>     -ENXIO: Getting or setting this attribute is not yet supported
> > 
> > 'not yet supported' as in something we'll implement later, or as in you
> > need to call this other function before you can access this state?
> > 
> Since only when the group is not KVM_DEV_ARM_PMU_GRP_IRQ, it will return
> -ENXIO. So what about this?
> 
> "-ENXIO: Unsupported attribute group"
> 
better,

-Christoffer

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

* [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device
@ 2015-12-18 10:00                     ` Christoffer Dall
  0 siblings, 0 replies; 135+ messages in thread
From: Christoffer Dall @ 2015-12-18 10:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Dec 17, 2015 at 03:22:50PM +0800, Shannon Zhao wrote:
> 
> 
> On 2015/12/17 4:33, Christoffer Dall wrote:
> > On Wed, Dec 16, 2015 at 04:06:49PM +0800, Shannon Zhao wrote:
> >> Hi,
> >>
> >> On 2015/12/16 15:31, Shannon Zhao wrote:
> >>>>>>>>> But in this case, you're returning an error if it is *not* initialized.
> >>>>>>>>> I understand that in that case you cannot return an interrupt number (-1
> >>>>>>>>> would be weird), but returning -EBUSY feels even more weird.
> >>>>>>>>>
> >>>>>>>>> I'd settle for -ENOXIO, or something similar. Anyone having a better idea?
> >>>>>>>>>
> >>>>> ENXIO or ENODEV would be my choice too, and add that to the
> >>>>> Documentation clearly describing when this error code is used.
> >>>>>
> >>>>> By the way, why do you loop over all VCPUS to set the same value when
> >>>>> you can't do anything per VCPU anyway?  It seems to me it's either a
> >>>>> per-VM property (that you can store on the VM data structure) or it's a
> >>>>> true per-VCPU property?
> >>> This is a per-VCPU property. PMU interrupt could be PPI or SPI. For PPI
> >>> the interrupt numbers are same for each vcpu, while for SPI they are
> >>> different, so it needs to set them separately. I planned to support both
> >>> PPI and SPI. I think I should add support for SPI at this moment and let
> >>> users (QEMU) to set these interrupts for each one.
> >>
> >> How about below vPMU Documentation?
> >>
> >> ARM Virtual Performance Monitor Unit (vPMU)
> >> ===========================================
> >>
> >> Device types supported:
> >>   KVM_DEV_TYPE_ARM_PMU_V3         ARM Performance Monitor Unit v3
> >>
> >> Instantiate one PMU instance for per VCPU through this API.
> >>
> >> Groups:
> >>   KVM_DEV_ARM_PMU_GRP_IRQ
> >>   Attributes:
> >>     The attr field of kvm_device_attr encodes two values:
> >>     bits:     | 63 .... 32 | 31 .... 0 |
> >>     values:   | vcpu_index |  irq_num  |
> BTW, I change this Attribute to below format and pass vcpu_index through
> this Attribute while pass irq_num through kvm_device_attr.addr.
> Is it fine?
> 
>     bits:     | 63 .... 32 | 31 ....  0 |
>     values:   |  reserved  | vcpu_index |
> 
> >>     The irq_num describes the PMU overflow interrupt number for the
> >> specified
> >>     vcpu_index vcpu. This interrupt could be a PPI or SPI, but for one
> >> VM the
> >>     interrupt type must be same for each vcpu.
> > 
> > some formatting snafus that I expect come from pasting the text in an
> > e-mail client.
> > 
> >>
> >>   Errors:
> >>     -ENXIO: Getting or setting this attribute is not yet supported
> > 
> > 'not yet supported' as in something we'll implement later, or as in you
> > need to call this other function before you can access this state?
> > 
> Since only when the group is not KVM_DEV_ARM_PMU_GRP_IRQ, it will return
> -ENXIO. So what about this?
> 
> "-ENXIO: Unsupported attribute group"
> 
better,

-Christoffer

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

end of thread, other threads:[~2015-12-18 10:00 UTC | newest]

Thread overview: 135+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-15  8:49 [PATCH v7 00/19] KVM: ARM64: Add guest PMU support Shannon Zhao
2015-12-15  8:49 ` Shannon Zhao
2015-12-15  8:49 ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 01/19] ARM64: Move PMU register related defines to asm/pmu.h Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 11:34   ` Marc Zyngier
2015-12-15 11:34     ` Marc Zyngier
2015-12-15 11:44     ` Shannon Zhao
2015-12-15 11:44       ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 02/19] KVM: ARM64: Define PMU data structure for each vcpu Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 03/19] KVM: ARM64: Add offset defines for PMU registers Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 04/19] KVM: ARM64: Add access handler for PMCR register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 05/19] KVM: ARM64: Add access handler for PMSELR register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 06/19] KVM: ARM64: Add access handler for PMCEID0 and PMCEID1 register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 14:20   ` Marc Zyngier
2015-12-15 14:20     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 07/19] KVM: ARM64: PMU: Add perf event map and introduce perf event creating function Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-17 15:22   ` Mark Rutland
2015-12-17 15:22     ` Mark Rutland
2015-12-17 15:30     ` Marc Zyngier
2015-12-17 15:30       ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 13:43   ` Marc Zyngier
2015-12-15 13:43     ` Marc Zyngier
2015-12-15 14:26   ` Marc Zyngier
2015-12-15 14:26     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 09/19] KVM: ARM64: Add access handler for event counter register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 13:44   ` Marc Zyngier
2015-12-15 13:44     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 10/19] KVM: ARM64: Add access handler for PMCNTENSET and PMCNTENCLR register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 13:56   ` Marc Zyngier
2015-12-15 13:56     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 11/19] KVM: ARM64: Add access handler for PMINTENSET and PMINTENCLR register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 14:02   ` Marc Zyngier
2015-12-15 14:02     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 12/19] KVM: ARM64: Add access handler for PMOVSSET and PMOVSCLR register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 14:06   ` Marc Zyngier
2015-12-15 14:06     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 13/19] KVM: ARM64: Add access handler for PMSWINC register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 14:36   ` Marc Zyngier
2015-12-15 14:36     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 14/19] KVM: ARM64: Add helper to handle PMCR register bits Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 15/19] KVM: ARM64: Add access handler for PMUSERENR register Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 14:58   ` Marc Zyngier
2015-12-15 14:58     ` Marc Zyngier
2015-12-15 15:59     ` Shannon Zhao
2015-12-15 15:59       ` Shannon Zhao
2015-12-15 16:02       ` Marc Zyngier
2015-12-15 16:02         ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 16/19] KVM: ARM64: Add PMU overflow interrupt routing Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 15:19   ` Marc Zyngier
2015-12-15 15:19     ` Marc Zyngier
2015-12-15  8:49 ` [PATCH v7 17/19] KVM: ARM64: Reset PMU state when resetting vcpu Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 18/19] KVM: ARM64: Free perf event of PMU when destroying vcpu Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49 ` [PATCH v7 19/19] KVM: ARM64: Add a new kvm ARM PMU device Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15  8:49   ` Shannon Zhao
2015-12-15 15:33   ` Marc Zyngier
2015-12-15 15:33     ` Marc Zyngier
2015-12-15 15:50     ` Shannon Zhao
2015-12-15 15:50       ` Shannon Zhao
2015-12-15 15:59       ` Marc Zyngier
2015-12-15 15:59         ` Marc Zyngier
2015-12-15 17:50         ` Andrew Jones
2015-12-15 17:50           ` Andrew Jones
2015-12-15 17:50           ` [Qemu-devel] " Andrew Jones
2015-12-15 20:47         ` Christoffer Dall
2015-12-15 20:47           ` Christoffer Dall
2015-12-16  7:31           ` Shannon Zhao
2015-12-16  7:31             ` Shannon Zhao
2015-12-16  7:31             ` Shannon Zhao
2015-12-16  8:06             ` Shannon Zhao
2015-12-16  8:06               ` Shannon Zhao
2015-12-16  9:04               ` Marc Zyngier
2015-12-16  9:04                 ` Marc Zyngier
2015-12-16  9:29                 ` Shannon Zhao
2015-12-16  9:29                   ` Shannon Zhao
2015-12-16  9:29                   ` Shannon Zhao
2015-12-16 20:33               ` Christoffer Dall
2015-12-16 20:33                 ` Christoffer Dall
2015-12-17  7:22                 ` Shannon Zhao
2015-12-17  7:22                   ` Shannon Zhao
2015-12-17  7:22                   ` Shannon Zhao
2015-12-17  8:33                   ` Marc Zyngier
2015-12-17  8:33                     ` Marc Zyngier
2015-12-17  8:33                     ` Marc Zyngier
2015-12-17  8:41                     ` Shannon Zhao
2015-12-17  8:41                       ` Shannon Zhao
2015-12-17  8:41                       ` Shannon Zhao
2015-12-17  9:38                       ` Marc Zyngier
2015-12-17  9:38                         ` Marc Zyngier
2015-12-17 10:10                         ` Shannon Zhao
2015-12-17 10:10                           ` Shannon Zhao
2015-12-17 10:10                           ` Shannon Zhao
2015-12-17 10:38                           ` Marc Zyngier
2015-12-17 10:38                             ` Marc Zyngier
2015-12-18 10:00                   ` Christoffer Dall
2015-12-18 10:00                     ` Christoffer Dall
2015-12-15 15:41 ` [PATCH v7 00/19] KVM: ARM64: Add guest PMU support Marc Zyngier
2015-12-15 15:41   ` 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.