[PATCH v1 00/28] x86: initial SVM AVIC support

dmukhin@ford.com posted 28 patches 5 hours ago
Only 27 patches received!
CHANGELOG.md                             |   3 +
MAINTAINERS                              |  11 +
docs/misc/xen-command-line.pandoc        |  23 +-
xen/arch/x86/cpu-policy.c                |   3 +-
xen/arch/x86/domctl.c                    |  24 +-
xen/arch/x86/hvm/emulate.c               |   5 +
xen/arch/x86/hvm/hvm.c                   |  74 +-
xen/arch/x86/hvm/svm/Makefile            |   1 +
xen/arch/x86/hvm/svm/avic.c              | 921 +++++++++++++++++++++++
xen/arch/x86/hvm/svm/avic.h              |  41 +
xen/arch/x86/hvm/svm/intr.c              |  22 +
xen/arch/x86/hvm/svm/nestedsvm.c         |   9 +-
xen/arch/x86/hvm/svm/svm.c               | 186 ++++-
xen/arch/x86/hvm/svm/svm.h               |   2 +
xen/arch/x86/hvm/svm/vmcb.c              |  29 +-
xen/arch/x86/hvm/svm/vmcb.h              |  27 +-
xen/arch/x86/hvm/vlapic.c                |  25 +-
xen/arch/x86/hvm/vmx/vmx.c               |   4 +
xen/arch/x86/include/asm/apic.h          |   3 +-
xen/arch/x86/include/asm/apicdef.h       |   2 +-
xen/arch/x86/include/asm/hvm/hvm.h       |  47 +-
xen/arch/x86/include/asm/hvm/svm-types.h |  31 +
xen/arch/x86/include/asm/hvm/svm.h       |   4 +
xen/arch/x86/include/asm/hvm/vlapic.h    |   1 +
xen/arch/x86/include/asm/msr-index.h     |   1 +
xen/arch/x86/irq.c                       |  24 +
xen/arch/x86/time.c                      |   2 +-
xen/include/public/domctl.h              |   2 +
28 files changed, 1411 insertions(+), 116 deletions(-)
create mode 100644 xen/arch/x86/hvm/svm/avic.c
create mode 100644 xen/arch/x86/hvm/svm/avic.h
[PATCH v1 00/28] x86: initial SVM AVIC support
Posted by dmukhin@ford.com 5 hours ago
Overview
========

Modern AMD processors provide hardware-assisted LAPIC virtualization
support known as AVIC (Advanced Virtual Interrupt Controller). See
"15.29 Advanced Virtual Interrupt Controller" in [1].

The main objective is to improve interrupt delivery for a given VM
by avoiding expensive LAPIC emulation in hypervisor.

At a high-level, there are several types of interrupts needed to be
managed for a Xen domain:
  (a) IPIs
  (b) Posted interrupts (Xen-to-domain, such as event channels)
  (c) External devices (MSI, needs coordination with IOMMU)

This initial implementation addresses (a) and (b).

Current limitations:
- Only vLAPIC in xAPIC mode with AVIC enabled
- No GALog support

Please see [2] for more details on the scope.

This work is loosely based on previously submitted work [3] and [4],
including AVIC support in Linux KVM.

The feature is experimental and disabled in the default configuration.

Patch Series
============

Basically the entire work is divided into three big series:
 (A) Current series: initial SVM AVIC [5]
 (B) XTF interrupt latency test [6]
 (C) XTF infra in public CI [5]

For this AVIC series:

 Patches 1, 5, 6, 9, 11-16 introduce various cleanups and fixups.

 Patch 20 changes XEN_DOMCTL_debug_op implementation to allow
 more debug operations added (like enabling/disabling AVIC at
 run-time - used by the XTF test).

 Patches 2, 3, 4, 7, 8, 10, 17, 18-25 represent AVIC implementation
 including performance counters and run-time controls via debug
 hypercall.

 Patches 26-28 cover various documentation updates.

Testing
=======

Mainly, the patch series has been tested through public hardware runners.
Full CI run (including manually scheduled jobs) is available at [10].

Approach: I decided to write my own synthetic XTF [6] which runs as dom0
on a hardware target to capture some fine-grained metrics for IPIs and
posted interrupts (event channel).

System                                  | Test results
----------------------------------------+-------------
Zen2: Family 23 (0x17), Model 96 (0x60) | [7]
Zen3: Family 25 (0x19), Model 68 (0x44) | [8]
Zen5: Family 26 (0x1a), Model 36 (0x24) | [9]

Synthetic test:

    vCPU0                                     vCPU1
                                       executes some workload
 +-> t0
 |   |
 |   write ICR2 [*]
 r   write ICR
 e   |---------------- interrupt -----------> t0' = recv_tsc
 p   return from APIC emulation [*']          ISR
 e   |                                        t1' = handler_tsc
 a   t1
 t   |
 |   sync against ISR
 |   |
 +---+

First 1K samples is dropped, total number of samples is 20M.

IRQ delivery latency : t0' - t0
IRQ issue latency    : t1  - t0
IRQ handler latency  : t1' - t0'

[*]  For event channel that is EVTCHNOP_send hypercall.
[*'] For event channel that is return from the EVTCHNOP_send hypercall.

For all tested Zen2/Zen3/Zen5 targets there are overall improvements
w/ AVIC enabled: the test duration decreased, IPI delivery improved,
ISR latency improved.

Basically, AVIC optimizes long tails in the latency distribution leading
to more deterministic workload.

There's some peculiar behavior w.r.t. doorbell MSR which roughly takes 2us on
Zen5 - fallback to vcpu_kick() turned out to be faster. I added a run-time
configuration knob for a fallback, just in case.

There are also some outliers in the latency distributions which I haven't
ruled out yet: like look at max latency w/ and w/o AVIC in [7], [8], [9]: once
it a blue moon I've seen AVIC giving p99.999 values as a maximum (~15us vs
~45us for the entire 20M population).

Results for Zen5 target are more pronouced, so I am duplicating them below.

Zen5: Workload #1: IPI
----------------------

                    no AVIC                  |             AVIC
---------------------------------------------+------------------------------------
A: noaccel: IPI send latency (VCPU#0) (20000000 samples)
B: accel: IPI send latency (VCPU#0) (20000000 samples)
metric          cycles A              time A |        cycles B              time B
min                12240            6.131 us |             140               70 ns
avg                12955            6.489 us |             155               77 ns
p50       <        13000            6.512 us |  <          170               85 ns
p99       <        14000            7.013 us |  <          170               85 ns
p99.9     <        34000           17.031 us |  <          170               85 ns
p99.99    <        35000           17.532 us |  <          190               95 ns
p99.999   <        98000           49.092 us |  <        23000           11.521 us
max                99100           49.643 us |           86660           43.411 us
A: noaccel: IPI delivery latency (VCPU#0 -> VCPU#1) (20000000 samples)
B: accel: IPI delivery latency (VCPU#0 -> VCPU#1) (20000000 samples)
metric          cycles A              time A |        cycles B              time B
min                    0                0 ns |             620              310 ns
avg                 1402              702 ns |             626              313 ns
p50       <         1400              701 ns |  <          650              325 ns
p99       <         1500              751 ns |  <          700              350 ns
p99.9     <        20000           10.018 us |  <          700              350 ns
p99.99    <        20000           10.018 us |  <          700              350 ns
p99.999   <        71000           35.566 us |  <        23000           11.521 us
max                87740           43.952 us |           87000           43.581 us
A: noaccel: IPI handler latency (VCPU#1) (20000000 samples)
B: accel: IPI handler latency (VCPU#1) (20000000 samples)
metric          cycles A              time A |        cycles B              time B
min                15520            7.774 us |             160               80 ns
avg                16256            8.143 us |             174               87 ns
p50       <        17000            8.515 us |  <          190               95 ns
p99       <        17000            8.515 us |  <          190               95 ns
p99.9     <        17000            8.515 us |  <          190               95 ns
p99.99    <        17000            8.515 us |  <          190               95 ns
p99.999   <        23000           11.521 us |  <          190               95 ns
max                33880           16.971 us |             200              100 ns

Workload time                      182552 ms                               9919 ms
(20000000 samples)                                                    (~18x boost)

Zen5: Workload #2: evtchn
-------------------------

                    no AVIC                  |             AVIC
---------------------------------------------+------------------------------------
A: noaccel: evtchn send latency (VCPU#0) (20000000 samples)
B: accel: evtchn send latency (VCPU#0) (20000000 samples)
metric          cycles A              time A |        cycles B              time B
min                 5800            2.905 us |            6020            3.015 us
avg                 5988            2.999 us |            6204            3.107 us
p50       <         6000            3.005 us |  <         6200            3.105 us
p99       <         6100            3.055 us |  <         6200            3.105 us
p99.9     <        27000           13.525 us |  <        27000           13.525 us
p99.99    <        28000           14.026 us |  <        29000           14.527 us
p99.999   <        28000           14.026 us |  <        92000           46.086 us
max                92160           46.166 us |           92680           46.427 us
A: noaccel: evtchn delivery latency (VCPU#0 -> VCPU#1) (20000000 samples)
B: accel: evtchn delivery latency (VCPU#0 -> VCPU#1) (20000000 samples)
metric          cycles A              time A |        cycles B              time B
min                    0                0 ns |            5440            2.725 us
avg                 1412              707 ns |            5497            2.753 us
p50       <         1400              701 ns |  <         5600            2.805 us
p99       <         1500              751 ns |  <         5600            2.805 us
p99.9     <        19000            9.517 us |  <         6000            3.005 us
p99.99    <        19000            9.517 us |  <         6200            3.105 us
p99.999   <        71000           35.566 us |  <        28000           14.026 us
max                87600           43.882 us |           91760           45.966 us
A: noaccel: evtchn handler latency (VCPU#1) (20000000 samples)
B: accel: evtchn handler latency (VCPU#1) (20000000 samples)
metric          cycles A              time A |        cycles B              time B
min                15540            7.784 us |             180               90 ns
avg                15803            7.916 us |             184               92 ns
p50       <        16000            8.015 us |  <          190               95 ns
p99       <        16000            8.015 us |  <          210              105 ns
p99.9     <        16000            8.015 us |  <          210              105 ns
p99.99    <        16000            8.015 us |  <          210              105 ns
p99.999   <        24000           12.022 us |  <          210              105 ns
max                33120           16.591 us |             200              100 ns

metric          cycles A              time A |        cycles B              time B
min                    0                0 ns |            5400            2.705 us
avg                 1425              713 ns |            5467            2.738 us
p50       <         1500              751 ns |  <         5500            2.755 us
p99       <         1500              751 ns |  <         5600            2.805 us
p99.9     <        19000            9.517 us |  <         6000            3.005 us
p99.99    <        19000            9.517 us |  <         6200            3.105 us
p99.999   <        71000           35.566 us |  <        28000           14.026 us
max                87800           43.981 us |           91940           46.055 us

Workload time                      175951 ms                              62951 ms
(20000000 samples)                                                   (~2.5x boost)

Thanks a lot to Marek for hooking Zen5 runner to public CI.

Thanks a lot to Stefano and Andrew with advices and fixing the access to the
fleet of hardware runners.

References
==========

[1] AMD APM Volumes 1-5:
    https://docs.amd.com/v/u/en-US/40332_4.11_APM_Vol1-5
[2] Xen Summit 2026 SVM AVIC:
  - YouTube: https://www.youtube.com/watch?v=RhaJsOU_PIA&list=PLGe6RWOETgTQ
  - Slides: https://hosted-files.sched.co/xensummit2026/05/dmukhin_2026_x86_SVM_AVIC.pdf?_gl=1*158gk36*_gcl_au*MjU3OTQwMDQ2LjE3ODg0NzE3NDQ.*FPAU*MjU3OTQwMDQ2LjE3ODg0NzE3NDQ
[3] Archive v1:
    https://lore.kernel.org/xen-devel/1474264368-4104-1-git-send-email-suravee.suthikulpanit@amd.com/
[4] Archive v2:
    https://lore.kernel.org/xen-devel/20180507210753.2280-1-Janakarajan.Natarajan@amd.com/
[5] Current patch series:
    https://gitlab.com/xen-project/people/dmukhin/xen/-/commits/svm-avic-v3
[6] XTF interrupt latency test:
    https://gitlab.com/xen-project/people/dmukhin/xtf/-/tree/x86_64-ipi-latency?ref_type=heads
[7] Zen2: Family 23 (0x17), Model 96 (0x60): interrupt latency results:
    https://gist.github.com/dmkhn/289f1af656cce74c0fbc81642727a2a4
[8] Zen3: Family 25 (0x19), Model 68 (0x44): interrupt latency results:
    https://gist.github.com/dmkhn/9192105efc49cfedd15e2820b8ad23fd
[9] Zen5: Family 26 (0x1a), Model 36 (0x24): interrupt latency results:
    https://gist.github.com/dmkhn/e9f50b43cbc48b82175ec517d6cfe6f5
[10] CI:
    https://gitlab.com/xen-project/people/dmukhin/xen/-/pipelines/3025987819

Denis Mukhin (28):
  x86/hvm: move SVM feature printout to a separate function
  x86/hvm: report SVM AVIC support
  x86/hvm: report SVM x2AVIC support
  x86/hvm: avic: add domain state initialization
  x86/hvm: cleanup svm_create_vmcb()
  x86/hvm: introduce vlapic_reg_read()
  x86/hvm: avic: add VMCB state initialization
  x86/hvm: avic: add AVIC_INCOMP_IPI VMEXIT handler
  x86/hvm: fix hvm_emulate_one_vm_event() definition
  x86/hvm: avic: add AVIC_NOACCEL VMEXIT handler
  x86/hvm: introduce vcpu_is_vlapic_tpr_emulated()
  x86: apic: use APIC_EIO_ACK instead of open-coded 0
  x86/time: fix typo s/interruopt/interrupt/
  x86/hvm: vlapic: update signatures of both vlapic_{clear,test}_*
  x86/hvm: vlapic: add checks before posted interrupt delivery
  x86/hvm: move VINTR disable to svm_clear_intr_window()
  x86/hvm: avic: route interrupt delivery to vCPU
  x86/hvm: add facility to print hardware-assisted vLAPIC info
  x86/hvm: avic: enable SVM AVIC statistics reporting
  x86/hvm: rework XEN_DOMCTL_debug_op
  x86/hvm: enable debug hypercall for posted interrupts
  x86/hvm: avic: ensure SVM AVIC supports xAPIC operation only
  x86/hvm: avic: enable vLAPIC mode switch hook
  x86/hvm: avic: ensure SVM AVIC is disabled with nested guest
  x86/hvm: avic: account for AMD erratum 1235
  docs: add coverage for svm_avic=
  CHANGELOG.md: add note on initial SVM AVIC support
  MAINTAINERS: add myself as SVM AVIC reviewer

 CHANGELOG.md                             |   3 +
 MAINTAINERS                              |  11 +
 docs/misc/xen-command-line.pandoc        |  23 +-
 xen/arch/x86/cpu-policy.c                |   3 +-
 xen/arch/x86/domctl.c                    |  24 +-
 xen/arch/x86/hvm/emulate.c               |   5 +
 xen/arch/x86/hvm/hvm.c                   |  74 +-
 xen/arch/x86/hvm/svm/Makefile            |   1 +
 xen/arch/x86/hvm/svm/avic.c              | 921 +++++++++++++++++++++++
 xen/arch/x86/hvm/svm/avic.h              |  41 +
 xen/arch/x86/hvm/svm/intr.c              |  22 +
 xen/arch/x86/hvm/svm/nestedsvm.c         |   9 +-
 xen/arch/x86/hvm/svm/svm.c               | 186 ++++-
 xen/arch/x86/hvm/svm/svm.h               |   2 +
 xen/arch/x86/hvm/svm/vmcb.c              |  29 +-
 xen/arch/x86/hvm/svm/vmcb.h              |  27 +-
 xen/arch/x86/hvm/vlapic.c                |  25 +-
 xen/arch/x86/hvm/vmx/vmx.c               |   4 +
 xen/arch/x86/include/asm/apic.h          |   3 +-
 xen/arch/x86/include/asm/apicdef.h       |   2 +-
 xen/arch/x86/include/asm/hvm/hvm.h       |  47 +-
 xen/arch/x86/include/asm/hvm/svm-types.h |  31 +
 xen/arch/x86/include/asm/hvm/svm.h       |   4 +
 xen/arch/x86/include/asm/hvm/vlapic.h    |   1 +
 xen/arch/x86/include/asm/msr-index.h     |   1 +
 xen/arch/x86/irq.c                       |  24 +
 xen/arch/x86/time.c                      |   2 +-
 xen/include/public/domctl.h              |   2 +
 28 files changed, 1411 insertions(+), 116 deletions(-)
 create mode 100644 xen/arch/x86/hvm/svm/avic.c
 create mode 100644 xen/arch/x86/hvm/svm/avic.h

-- 
2.55.0