powerpc/kvm/xive: Add more debugfs queues info
Subsystems (3)
PATCH v4 1/6 powerpc/kvm/xive: Add more debugfs queues info
Add details about enabled queues and escalation interrupts
--- arch/powerpc/kvm/book3s_xive.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
arch/powerpc/kvm/book3s_xive.c +28 -0
@@ -1795,6 +1795,7 @@ static int xive_debug_show(struct seq_file *m, void *private)kvm_for_each_vcpu (i, vcpu, kvm) {struct kvmppc_xive_vcpu *xc = vcpu->arch.xive_vcpu; +unsigned int i;if (!xc)continue ;
@@ -1804,6 +1805,33 @@ static int xive_debug_show(struct seq_file *m, void *private) xc->server_num, xc->cppr, xc->hw_cppr, xc->mfrr, xc->pending, xc->stat_rm_h_xirr, xc->stat_vm_h_xirr); +for (i =0 ; i <KVMPPC_XIVE_Q_COUNT ; i++) { +struct xive_q *q = &xc->queues[i]; +u32 i0, i1, idx; + +if (!q->qpage && !xc->esc_virq[i]) +continue ; + +seq_printf (m," [q%d]: " , i); + +if (q->qpage) { + idx = q->idx; + i0 =be32_to_cpup (q->qpage + idx); + idx = (idx +1 ) & q->msk; + i1 =be32_to_cpup (q->qpage + idx); +seq_printf (m,"T=%d %08x %08x... \n" , q->toggle, i0, i1); + } +if (xc->esc_virq[i]) { +struct irq_data *d =irq_get_irq_data (xc->esc_virq[i]); +struct xive_irq_data *xd =irq_data_get_irq_handler_data (d); +u64 pq =xive_vm_esb_load (xd,XIVE_ESB_GET ); +seq_printf (m,"E:%c%c I(%d:%llx:%llx)" , + (pq &XIVE_ESB_VAL_P ) ?'P' :'p' , + (pq &XIVE_ESB_VAL_Q ) ?'Q' :'q' , + xc->esc_virq[i], pq, xd->eoi_page); +seq_printf (m,"\n" ); + } + } t_rm_h_xirr += xc->stat_rm_h_xirr; t_rm_h_ipoll += xc->stat_rm_h_ipoll;
Signature · 1 line
2.14.3
PATCH v4 2/6 powerpc/kvm/xive: Enable use of the new "single escalation" feature
That feature, provided by Power9 DDD2.0 and later, when supported by newer OPAL versions, allows to sacrifice a queue (priority 7) in favor of merging all the escalation interrupts of the queues of a single VP into a single interrupt.
This reduces the number of host interrupts used up by KVM guests especially when those guests use multiple priorities.
It will also enable a future change to control the masking of the escalation interrupts more precisely to avoid spurrious ones.
--- arch/powerpc/include/asm/opal-api.h | 1 + arch/powerpc/include/asm/xive.h | 3 ++- arch/powerpc/kvm/book3s_xive.c | 48 ++++++++++++++++++++++++------------- arch/powerpc/kvm/book3s_xive.h | 15 +++++------- arch/powerpc/sysdev/xive/native.c | 18 ++++++++++++-- 5 files changed, 57 insertions(+), 28 deletions(-)
arch/powerpc/include/asm/opal-api.h +1 -0
@@ -1073,6 +1073,7 @@ enum {/* Flags for OPAL_XIVE_GET/SET_VP_INFO */ enum {OPAL_XIVE_VP_ENABLED =0x00000001 , +OPAL_XIVE_VP_SINGLE_ESCALATION =0x00000002 , };/* "Any chip" replacement for chip ID for allocation functions */
arch/powerpc/include/asm/xive.h +2 -1
@@ -111,9 +111,10 @@ extern void xive_native_disable_queue(u32 vp_id, struct xive_q *q, u8 prio);extern void xive_native_sync_source (u32 hw_irq);extern bool is_xive_irq (struct irq_chip *chip); -extern int xive_native_enable_vp (u32 vp_id); +extern int xive_native_enable_vp (u32 vp_id,bool single_escalation);extern int xive_native_disable_vp (u32 vp_id);extern int xive_native_get_vp_info (u32 vp_id,u32 *out_cam_id,u32 *out_chip_id); +extern bool xive_native_has_single_escalation (void );#else
arch/powerpc/kvm/book3s_xive.c +32 -16
111 lines not on this page · raw message
arch/powerpc/kvm/book3s_xive.h +6 -9
@@ -120,6 +120,8 @@ struct kvmppc_xive {u32 q_order;u32 q_page_order; +/* Flags */ +u8 single_escalation; };#define KVMPPC_XIVE_Q_COUNT 8
@@ -201,25 +203,20 @@ static inline struct kvmppc_xive_src_block *kvmppc_xive_find_source(struct kvmpp* is as follow. * * Guest request for 0...6 are honored. Guest request for anything -* higher results in a priority of 7 being applied. -* -* However, when XIRR is returned via H_XIRR, 7 is translated to 0xb -* in order to match AIX expectations +* higher results in a priority of 6 being applied. * * Similar mapping is done for CPPR values */ static inline u8 xive_prio_from_guest (u8 prio) { -if (prio =0xff || prio <8 ) +if (prio =0xff || prio <6 )return prio; -return 7 ; +return 6 ; }static inline u8 xive_prio_to_guest (u8 prio) { -if (prio =0xff || prio <7 ) -return prio; -return 0xb ; +return prio; }static inline u32 __xive_read_eq (__be32 *qpage,u32 msk,u32 *idx,u32 *toggle)
arch/powerpc/sysdev/xive/native.c +16 -2
@@ -42,6 +42,7 @@ static u32 xive_provision_chip_count;static u32 xive_queue_shift;static u32 xive_pool_vps =XIVE_INVALID_VP ;static struct kmem_cache *xive_provision_cache; +static bool xive_has_single_esc;int xive_native_populate_irq_data (u32 hw_irq,struct xive_irq_data *data) {
@@ -571,6 +572,10 @@ bool __init xive_native_init(void)break ; } +/* Do we support single escalation */ +if (of_get_property (np,"single-escalation-support" ,NULL ) !=NULL ) + xive_has_single_esc = true; +/* Configure Thread Management areas for KVM */ for_each_possible_cpu (cpu)kvmppc_set_xive_tima (cpu, r.start, tima);
@@ -667,12 +672,15 @@ void xive_native_free_vp_block(u32 vp_base) }EXPORT_SYMBOL_GPL (xive_native_free_vp_block); -int xive_native_enable_vp (u32 vp_id) +int xive_native_enable_vp (u32 vp_id,bool single_escalation) {s64 rc; +u64 flags =OPAL_XIVE_VP_ENABLED ; +if (single_escalation) + flags |=OPAL_XIVE_VP_SINGLE_ESCALATION ;for (;;) { - rc =opal_xive_set_vp_info (vp_id,OPAL_XIVE_VP_ENABLED ,0 ); + rc =opal_xive_set_vp_info (vp_id, flags,0 );if (rc !=OPAL_BUSY )break ;msleep (1 );
@@ -710,3 +718,9 @@ int xive_native_get_vp_info(u32 vp_id, u32 *out_cam_id, u32 *out_chip_id)return 0 ; }EXPORT_SYMBOL_GPL (xive_native_get_vp_info); + +bool xive_native_has_single_escalation (void ) +{ +return xive_has_single_esc; +} +EXPORT_SYMBOL_GPL (xive_native_has_single_escalation);
Signature · 1 line
2.14.3
PATCH v4 3/6 powerpc/kvm/xive: Don't use existing "prodded" flag for xive escalations
In reply to Benjamin HerrenschmidtThe prodded flag is only cleared at the beginning of H_CEDE, so every time we have an escalation, we will cause the *next* H_CEDE to return immediately.
Instead use a dedicated "irq_pending" flag to indicate that a guest interrupt is pending for the VCPU. We don't reuse the existing exception bitmap as to avoid expensive atomic ops.
--- arch/powerpc/include/asm/kvm_host.h | 1 + arch/powerpc/kernel/asm-offsets.c | 1 + arch/powerpc/kvm/book3s_hv.c | 2 +- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 10 ++++++++++ arch/powerpc/kvm/book3s_xive.c | 3 +-- 5 files changed, 14 insertions(+), 3 deletions(-)
arch/powerpc/include/asm/kvm_host.h +1 -0
@@ -709,6 +709,7 @@ struct kvm_vcpu_arch {u8 ceded;u8 prodded;u8 doorbell_request; +u8 irq_pending;/* Used by XIVE to signal pending guest irqs */ u32 last_inst;struct swait_queue_head *wqp;
arch/powerpc/kernel/asm-offsets.c +1 -0
@@ -514,6 +514,7 @@ int main(void)OFFSET (VCPU_PENDING_EXC , kvm_vcpu, arch.pending_exceptions);OFFSET (VCPU_CEDED , kvm_vcpu, arch.ceded);OFFSET (VCPU_PRODDED , kvm_vcpu, arch.prodded); +OFFSET (VCPU_IRQ_PENDING , kvm_vcpu, arch.irq_pending);OFFSET (VCPU_DBELL_REQ , kvm_vcpu, arch.doorbell_request);OFFSET (VCPU_MMCR , kvm_vcpu, arch.mmcr);OFFSET (VCPU_PMC , kvm_vcpu, arch.pmc);
arch/powerpc/kvm/book3s_hv.c +1 -1
@@ -2987,7 +2987,7 @@ static inline bool xive_interrupt_pending(struct kvm_vcpu *vcpu) {if (!xive_enabled ())return false; -return vcpu->arch.xive_saved_state.pipr < +return vcpu->arch.irq_pending || vcpu->arch.xive_saved_state.pipr < vcpu->arch.xive_saved_state.cppr; }#else
arch/powerpc/kvm/book3s_hv_rmhandlers.S +10 -0
@@ -1033,6 +1033,16 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300) li r9, 1 stw r9, VCPU_XIVE_PUSHED(r4) eieio + + /* + * We clear the irq_pending flag. There is a small chance of a + * race vs. the escalation interrupt happening on another + * processor setting it again, but the only consequence is to + * cause a spurrious wakeup on the next H_CEDE which is not an + * issue. + */ + li r0,0 + stb r0, VCPU_IRQ_PENDING(r4) no_xive: #endif /* CONFIG_KVM_XICS */
arch/powerpc/kvm/book3s_xive.c +1 -2
@@ -84,8 +84,7 @@ static irqreturn_t xive_esc_irq(int irq, void *data) {struct kvm_vcpu *vcpu = data; -/* We use the existing H_PROD mechanism to wake up the target */ - vcpu->arch.prodded =1 ; + vcpu->arch.irq_pending =1 ;smp_mb ();if (vcpu->arch.ceded)kvmppc_fast_vcpu_kick (vcpu);
Signature · 1 line
2.14.3
PATCH v4 4/6 powerpc/kvm/xive: Check DR not IR to chose real vs virt mode MMIOs
In reply to Benjamin Herrenschmidt--- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kvm/book3s_hv_rmhandlers.S +1 -1
@@ -1442,7 +1442,7 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ li r7, TM_SPC_PULL_OS_CTX li r6, TM_QW1_OS mfmsr r0 - andi. r0, r0, MSR_IR /* in real mode? */ + andi. r0, r0, MSR_DR /* in real mode? */ beq 2f ld r10, HSTATE_XIVE_TIMA_VIRT(r13) cmpldi cr0, r10, 0
Signature · 1 line
2.14.3
PATCH v4 5/6 powerpc/kvm/xive: Make xive_pushed a byte, not a word
In reply to Benjamin Herrenschmidt--- arch/powerpc/include/asm/kvm_host.h | 2 +- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-)
arch/powerpc/include/asm/kvm_host.h +1 -1
@@ -739,7 +739,7 @@ struct kvm_vcpu_arch {struct kvmppc_icp *icp;/* XICS presentation controller */ struct kvmppc_xive_vcpu *xive_vcpu;/* XIVE virtual CPU data */ __be32 xive_cam_word;/* Cooked W2 in proper endian with valid bit */ -u32 xive_pushed;/* Is the VP pushed on the physical CPU ? */ +u8 xive_pushed;/* Is the VP pushed on the physical CPU ? */ union xive_tma_w01 xive_saved_state;/* W0..1 of XIVE thread state */ #endif
arch/powerpc/kvm/book3s_hv_rmhandlers.S +3 -3
@@ -1031,7 +1031,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_300) li r9, TM_QW1_OS + TM_WORD2 stwcix r11,r9,r10 li r9, 1 - stw r9, VCPU_XIVE_PUSHED(r4) + stb r9, VCPU_XIVE_PUSHED(r4) eieio /*
@@ -1436,7 +1436,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ #ifdef CONFIG_KVM_XICS /* We are exiting, pull the VP from the XIVE */ - lwz r0, VCPU_XIVE_PUSHED(r9) + lbz r0, VCPU_XIVE_PUSHED(r9) cmpwi cr0, r0, 0 beq 1f li r7, TM_SPC_PULL_OS_CTX
@@ -1465,7 +1465,7 @@ guest_exit_cont: /* r9 = vcpu, r12 = trap, r13 = paca */ /* Fixup some of the state for the next load */ li r10, 0 li r0, 0xff - stw r10, VCPU_XIVE_PUSHED(r9) + stb r10, VCPU_XIVE_PUSHED(r9) stb r10, (VCPU_XIVE_SAVED_STATE+3)(r9) stb r0, (VCPU_XIVE_SAVED_STATE+4)(r9) eieio
Signature · 1 line
2.14.3
PATCH v4 6/6 powerpc/kvm/xive: Keep escalation interrupt masked unless ceded
In reply to Benjamin HerrenschmidtThis works on top of the single escalation support. When in single escalation, with this change, we will keep the escalation interrupt disabled unless the VCPU is in H_CEDE (idle). In any other case, we know the VCPU will be rescheduled and thus there is no need to take escalation interrupts in the host whenever a guest interrupt fires.
--- arch/powerpc/include/asm/kvm_host.h | 3 ++ arch/powerpc/kernel/asm-offsets.c | 3 ++ arch/powerpc/kvm/book3s_hv_rmhandlers.S | 62 ++++++++++++++++++++++++++++++++- arch/powerpc/kvm/book3s_xive.c | 30 ++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-)
arch/powerpc/include/asm/kvm_host.h +3 -0
@@ -740,7 +740,10 @@ struct kvm_vcpu_arch {struct kvmppc_xive_vcpu *xive_vcpu;/* XIVE virtual CPU data */ __be32 xive_cam_word;/* Cooked W2 in proper endian with valid bit */ u8 xive_pushed;/* Is the VP pushed on the physical CPU ? */ +u8 xive_esc_on;/* Is the escalation irq enabled ? */ union xive_tma_w01 xive_saved_state;/* W0..1 of XIVE thread state */ +u64 xive_esc_raddr;/* Escalation interrupt ESB real addr */ +u64 xive_esc_vaddr;/* Escalation interrupt ESB virt addr */ #endif #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
arch/powerpc/kernel/asm-offsets.c +3 -0
@@ -734,6 +734,9 @@ int main(void)DEFINE (VCPU_XIVE_CAM_WORD , offsetof(struct kvm_vcpu , arch.xive_cam_word)); DEFINE(VCPU_XIVE_PUSHED, offsetof(struct kvm_vcpu, arch.xive_pushed)); + DEFINE(VCPU_XIVE_ESC_ON, offsetof(struct kvm_vcpu, arch.xive_esc_on)); + DEFINE(VCPU_XIVE_ESC_RADDR, offsetof(struct kvm_vcpu, arch.xive_esc_raddr)); + DEFINE(VCPU_XIVE_ESC_VADDR, offsetof(struct kvm_vcpu, arch.xive_esc_vaddr));#endif #ifdef CONFIG_KVM_EXIT_TIMING
arch/powerpc/kvm/book3s_hv_rmhandlers.S +61 -1
74 lines not on this page · raw message
arch/powerpc/kvm/book3s_xive.c +30 -0
@@ -89,6 +89,17 @@ static irqreturn_t xive_esc_irq(int irq, void *data)if (vcpu->arch.ceded)kvmppc_fast_vcpu_kick (vcpu); +/* Since we have the no-EOI flag, the interrupt is effectively +* disabled now. Clearing xive_esc_on means we won't bother +* doing so on the next entry. +* +* This also allows the entry code to know that if a PQ combination +* of 10 is observed while xive_esc_on is true, it means the queue +* contains an unprocessed escalation interrupt. We don't make use of +* that knowledge today but might (see comment in book3s_hv_rmhandler.S) +*/ + vcpu->arch.xive_esc_on = false; +return IRQ_HANDLED ; }
@@ -134,6 +145,25 @@ static int xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio) goto error; } xc->esc_virq_names[prio] = name; + +/* In single escalation mode, we grab the ESB MMIO of the +* interrupt and mask it. Also populate the VCPU v/raddr +* of the ESB page for use by asm entry/exit code. Finally +* set the XIVE_IRQ_NO_EOI flag which will prevent the +* core code from performing an EOI on the escalation +* interrupt, thus leaving it effectively masked after +* it fires once. +*/ +if (xc->xive->single_escalation) { +struct irq_data *d =irq_get_irq_data (xc->esc_virq[prio]); +struct xive_irq_data *xd =irq_data_get_irq_handler_data (d); + +xive_vm_esb_load (xd,XIVE_ESB_SET_PQ_01 ); + vcpu->arch.xive_esc_raddr = xd->eoi_page; + vcpu->arch.xive_esc_vaddr = (__force u64 )xd->eoi_mmio; + xd->flags |=XIVE_IRQ_NO_EOI ; + } +return 0 ; error:irq_dispose_mapping (xc->esc_virq[prio]);
Signature · 1 line
2.14.3