| /* |
| * Copyright 2017 Benjamin Herrenschmidt, IBM Corporation |
| * |
| * 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. |
| */ |
| |
| #ifndef _KVM_PPC_BOOK3S_XIVE_H |
| #define _KVM_PPC_BOOK3S_XIVE_H |
| |
| #ifdef CONFIG_KVM_XICS |
| #include "book3s_xics.h" |
| |
| /* |
| * State for one guest irq source. |
| * |
| * For each guest source we allocate a HW interrupt in the XIVE |
| * which we use for all SW triggers. It will be unused for |
| * pass-through but it's easier to keep around as the same |
| * guest interrupt can alternatively be emulated or pass-through |
| * if a physical device is hot unplugged and replaced with an |
| * emulated one. |
| * |
| * This state structure is very similar to the XICS one with |
| * additional XIVE specific tracking. |
| */ |
| struct kvmppc_xive_irq_state { |
| bool valid; /* Interrupt entry is valid */ |
| |
| u32 number; /* Guest IRQ number */ |
| u32 ipi_number; /* XIVE IPI HW number */ |
| struct xive_irq_data ipi_data; /* XIVE IPI associated data */ |
| u32 pt_number; /* XIVE Pass-through number if any */ |
| struct xive_irq_data *pt_data; /* XIVE Pass-through associated data */ |
| |
| /* Targetting as set by guest */ |
| u32 guest_server; /* Current guest selected target */ |
| u8 guest_priority; /* Guest set priority */ |
| u8 saved_priority; /* Saved priority when masking */ |
| |
| /* Actual targetting */ |
| u32 act_server; /* Actual server */ |
| u8 act_priority; /* Actual priority */ |
| |
| /* Various state bits */ |
| bool in_eoi; /* Synchronize with H_EOI */ |
| bool old_p; /* P bit state when masking */ |
| bool old_q; /* Q bit state when masking */ |
| bool lsi; /* level-sensitive interrupt */ |
| bool asserted; /* Only for emulated LSI: current state */ |
| |
| /* Saved for migration state */ |
| bool in_queue; |
| bool saved_p; |
| bool saved_q; |
| u8 saved_scan_prio; |
| }; |
| |
| /* Select the "right" interrupt (IPI vs. passthrough) */ |
| static inline void kvmppc_xive_select_irq(struct kvmppc_xive_irq_state *state, |
| u32 *out_hw_irq, |
| struct xive_irq_data **out_xd) |
| { |
| if (state->pt_number) { |
| if (out_hw_irq) |
| *out_hw_irq = state->pt_number; |
| if (out_xd) |
| *out_xd = state->pt_data; |
| } else { |
| if (out_hw_irq) |
| *out_hw_irq = state->ipi_number; |
| if (out_xd) |
| *out_xd = &state->ipi_data; |
| } |
| } |
| |
| /* |
| * This corresponds to an "ICS" in XICS terminology, we use it |
| * as a mean to break up source information into multiple structures. |
| */ |
| struct kvmppc_xive_src_block { |
| arch_spinlock_t lock; |
| u16 id; |
| struct kvmppc_xive_irq_state irq_state[KVMPPC_XICS_IRQ_PER_ICS]; |
| }; |
| |
| |
| struct kvmppc_xive { |
| struct kvm *kvm; |
| struct kvm_device *dev; |
| struct dentry *dentry; |
| |
| /* VP block associated with the VM */ |
| u32 vp_base; |
| |
| /* Blocks of sources */ |
| struct kvmppc_xive_src_block *src_blocks[KVMPPC_XICS_MAX_ICS_ID + 1]; |
| u32 max_sbid; |
| |
| /* |
| * For state save, we lazily scan the queues on the first interrupt |
| * being migrated. We don't have a clean way to reset that flags |
| * so we keep track of the number of valid sources and how many of |
| * them were migrated so we can reset when all of them have been |
| * processed. |
| */ |
| u32 src_count; |
| u32 saved_src_count; |
| |
| /* |
| * Some irqs are delayed on restore until the source is created, |
| * keep track here of how many of them |
| */ |
| u32 delayed_irqs; |
| |
| /* Which queues (priorities) are in use by the guest */ |
| u8 qmap; |
| |
| /* Queue orders */ |
| u32 q_order; |
| u32 q_page_order; |
| |
| }; |
| |
| #define KVMPPC_XIVE_Q_COUNT 8 |
| |
| struct kvmppc_xive_vcpu { |
| struct kvmppc_xive *xive; |
| struct kvm_vcpu *vcpu; |
| bool valid; |
| |
| /* Server number. This is the HW CPU ID from a guest perspective */ |
| u32 server_num; |
| |
| /* |
| * HW VP corresponding to this VCPU. This is the base of the VP |
| * block plus the server number. |
| */ |
| u32 vp_id; |
| u32 vp_chip_id; |
| u32 vp_cam; |
| |
| /* IPI used for sending ... IPIs */ |
| u32 vp_ipi; |
| struct xive_irq_data vp_ipi_data; |
| |
| /* Local emulation state */ |
| uint8_t cppr; /* guest CPPR */ |
| uint8_t hw_cppr;/* Hardware CPPR */ |
| uint8_t mfrr; |
| uint8_t pending; |
| |
| /* Each VP has 8 queues though we only provision some */ |
| struct xive_q queues[KVMPPC_XIVE_Q_COUNT]; |
| u32 esc_virq[KVMPPC_XIVE_Q_COUNT]; |
| char *esc_virq_names[KVMPPC_XIVE_Q_COUNT]; |
| |
| /* Stash a delayed irq on restore from migration (see set_icp) */ |
| u32 delayed_irq; |
| |
| /* Stats */ |
| u64 stat_rm_h_xirr; |
| u64 stat_rm_h_ipoll; |
| u64 stat_rm_h_cppr; |
| u64 stat_rm_h_eoi; |
| u64 stat_rm_h_ipi; |
| u64 stat_vm_h_xirr; |
| u64 stat_vm_h_ipoll; |
| u64 stat_vm_h_cppr; |
| u64 stat_vm_h_eoi; |
| u64 stat_vm_h_ipi; |
| }; |
| |
| static inline struct kvm_vcpu *kvmppc_xive_find_server(struct kvm *kvm, u32 nr) |
| { |
| struct kvm_vcpu *vcpu = NULL; |
| int i; |
| |
| kvm_for_each_vcpu(i, vcpu, kvm) { |
| if (vcpu->arch.xive_vcpu && nr == vcpu->arch.xive_vcpu->server_num) |
| return vcpu; |
| } |
| return NULL; |
| } |
| |
| static inline struct kvmppc_xive_src_block *kvmppc_xive_find_source(struct kvmppc_xive *xive, |
| u32 irq, u16 *source) |
| { |
| u32 bid = irq >> KVMPPC_XICS_ICS_SHIFT; |
| u16 src = irq & KVMPPC_XICS_SRC_MASK; |
| |
| if (source) |
| *source = src; |
| if (bid > KVMPPC_XICS_MAX_ICS_ID) |
| return NULL; |
| return xive->src_blocks[bid]; |
| } |
| |
| /* |
| * Mapping between guest priorities and host priorities |
| * 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 |
| * |
| * Similar mapping is done for CPPR values |
| */ |
| static inline u8 xive_prio_from_guest(u8 prio) |
| { |
| if (prio == 0xff || prio < 8) |
| return prio; |
| return 7; |
| } |
| |
| static inline u8 xive_prio_to_guest(u8 prio) |
| { |
| if (prio == 0xff || prio < 7) |
| return prio; |
| return 0xb; |
| } |
| |
| static inline u32 __xive_read_eq(__be32 *qpage, u32 msk, u32 *idx, u32 *toggle) |
| { |
| u32 cur; |
| |
| if (!qpage) |
| return 0; |
| cur = be32_to_cpup(qpage + *idx); |
| if ((cur >> 31) == *toggle) |
| return 0; |
| *idx = (*idx + 1) & msk; |
| if (*idx == 0) |
| (*toggle) ^= 1; |
| return cur & 0x7fffffff; |
| } |
| |
| extern unsigned long xive_rm_h_xirr(struct kvm_vcpu *vcpu); |
| extern unsigned long xive_rm_h_ipoll(struct kvm_vcpu *vcpu, unsigned long server); |
| extern int xive_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server, |
| unsigned long mfrr); |
| extern int xive_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr); |
| extern int xive_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr); |
| |
| extern unsigned long (*__xive_vm_h_xirr)(struct kvm_vcpu *vcpu); |
| extern unsigned long (*__xive_vm_h_ipoll)(struct kvm_vcpu *vcpu, unsigned long server); |
| extern int (*__xive_vm_h_ipi)(struct kvm_vcpu *vcpu, unsigned long server, |
| unsigned long mfrr); |
| extern int (*__xive_vm_h_cppr)(struct kvm_vcpu *vcpu, unsigned long cppr); |
| extern int (*__xive_vm_h_eoi)(struct kvm_vcpu *vcpu, unsigned long xirr); |
| |
| #endif /* CONFIG_KVM_XICS */ |
| #endif /* _KVM_PPC_BOOK3S_XICS_H */ |