You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge remote-tracking branch 'remotes/powerpc/topic/xive' into kvm-ppc-next
This merges in the powerpc topic/xive branch to bring in the code for the in-kernel XICS interrupt controller emulation to use the new XIVE (eXternal Interrupt Virtualization Engine) hardware in the POWER9 chip directly, rather than via a XICS emulation in firmware. Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
@@ -55,6 +55,14 @@
|
||||
#define PPC_BITEXTRACT(bits, ppc_bit, dst_bit) \
|
||||
((((bits) >> PPC_BITLSHIFT(ppc_bit)) & 1) << (dst_bit))
|
||||
|
||||
#define PPC_BITLSHIFT32(be) (32 - 1 - (be))
|
||||
#define PPC_BIT32(bit) (1UL << PPC_BITLSHIFT32(bit))
|
||||
#define PPC_BITMASK32(bs, be) ((PPC_BIT32(bs) - PPC_BIT32(be))|PPC_BIT32(bs))
|
||||
|
||||
#define PPC_BITLSHIFT8(be) (8 - 1 - (be))
|
||||
#define PPC_BIT8(bit) (1UL << PPC_BITLSHIFT8(bit))
|
||||
#define PPC_BITMASK8(bs, be) ((PPC_BIT8(bs) - PPC_BIT8(be))|PPC_BIT8(bs))
|
||||
|
||||
#include <asm/barrier.h>
|
||||
|
||||
/* Macro for generating the ***_bits() functions */
|
||||
|
||||
@@ -192,24 +192,8 @@ DEF_MMIO_OUT_D(out_le32, 32, stw);
|
||||
|
||||
#endif /* __BIG_ENDIAN */
|
||||
|
||||
/*
|
||||
* Cache inhibitied accessors for use in real mode, you don't want to use these
|
||||
* unless you know what you're doing.
|
||||
*
|
||||
* NB. These use the cpu byte ordering.
|
||||
*/
|
||||
DEF_MMIO_OUT_X(out_rm8, 8, stbcix);
|
||||
DEF_MMIO_OUT_X(out_rm16, 16, sthcix);
|
||||
DEF_MMIO_OUT_X(out_rm32, 32, stwcix);
|
||||
DEF_MMIO_IN_X(in_rm8, 8, lbzcix);
|
||||
DEF_MMIO_IN_X(in_rm16, 16, lhzcix);
|
||||
DEF_MMIO_IN_X(in_rm32, 32, lwzcix);
|
||||
|
||||
#ifdef __powerpc64__
|
||||
|
||||
DEF_MMIO_OUT_X(out_rm64, 64, stdcix);
|
||||
DEF_MMIO_IN_X(in_rm64, 64, ldcix);
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
DEF_MMIO_OUT_D(out_be64, 64, std);
|
||||
DEF_MMIO_IN_D(in_be64, 64, ld);
|
||||
@@ -242,35 +226,6 @@ static inline void out_be64(volatile u64 __iomem *addr, u64 val)
|
||||
#endif
|
||||
#endif /* __powerpc64__ */
|
||||
|
||||
|
||||
/*
|
||||
* Simple Cache inhibited accessors
|
||||
* Unlike the DEF_MMIO_* macros, these don't include any h/w memory
|
||||
* barriers, callers need to manage memory barriers on their own.
|
||||
* These can only be used in hypervisor real mode.
|
||||
*/
|
||||
|
||||
static inline u32 _lwzcix(unsigned long addr)
|
||||
{
|
||||
u32 ret;
|
||||
|
||||
__asm__ __volatile__("lwzcix %0,0, %1"
|
||||
: "=r" (ret) : "r" (addr) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void _stbcix(u64 addr, u8 val)
|
||||
{
|
||||
__asm__ __volatile__("stbcix %0,0,%1"
|
||||
: : "r" (val), "r" (addr) : "memory");
|
||||
}
|
||||
|
||||
static inline void _stwcix(u64 addr, u32 val)
|
||||
{
|
||||
__asm__ __volatile__("stwcix %0,0,%1"
|
||||
: : "r" (val), "r" (addr) : "memory");
|
||||
}
|
||||
|
||||
/*
|
||||
* Low level IO stream instructions are defined out of line for now
|
||||
*/
|
||||
@@ -417,15 +372,64 @@ static inline void __raw_writeq(unsigned long v, volatile void __iomem *addr)
|
||||
}
|
||||
|
||||
/*
|
||||
* Real mode version of the above. stdcix is only supposed to be used
|
||||
* in hypervisor real mode as per the architecture spec.
|
||||
* Real mode versions of the above. Those instructions are only supposed
|
||||
* to be used in hypervisor real mode as per the architecture spec.
|
||||
*/
|
||||
static inline void __raw_rm_writeb(u8 val, volatile void __iomem *paddr)
|
||||
{
|
||||
__asm__ __volatile__("stbcix %0,0,%1"
|
||||
: : "r" (val), "r" (paddr) : "memory");
|
||||
}
|
||||
|
||||
static inline void __raw_rm_writew(u16 val, volatile void __iomem *paddr)
|
||||
{
|
||||
__asm__ __volatile__("sthcix %0,0,%1"
|
||||
: : "r" (val), "r" (paddr) : "memory");
|
||||
}
|
||||
|
||||
static inline void __raw_rm_writel(u32 val, volatile void __iomem *paddr)
|
||||
{
|
||||
__asm__ __volatile__("stwcix %0,0,%1"
|
||||
: : "r" (val), "r" (paddr) : "memory");
|
||||
}
|
||||
|
||||
static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
|
||||
{
|
||||
__asm__ __volatile__("stdcix %0,0,%1"
|
||||
: : "r" (val), "r" (paddr) : "memory");
|
||||
}
|
||||
|
||||
static inline u8 __raw_rm_readb(volatile void __iomem *paddr)
|
||||
{
|
||||
u8 ret;
|
||||
__asm__ __volatile__("lbzcix %0,0, %1"
|
||||
: "=r" (ret) : "r" (paddr) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u16 __raw_rm_readw(volatile void __iomem *paddr)
|
||||
{
|
||||
u16 ret;
|
||||
__asm__ __volatile__("lhzcix %0,0, %1"
|
||||
: "=r" (ret) : "r" (paddr) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u32 __raw_rm_readl(volatile void __iomem *paddr)
|
||||
{
|
||||
u32 ret;
|
||||
__asm__ __volatile__("lwzcix %0,0, %1"
|
||||
: "=r" (ret) : "r" (paddr) : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u64 __raw_rm_readq(volatile void __iomem *paddr)
|
||||
{
|
||||
u64 ret;
|
||||
__asm__ __volatile__("ldcix %0,0, %1"
|
||||
: "=r" (ret) : "r" (paddr) : "memory");
|
||||
return ret;
|
||||
}
|
||||
#endif /* __powerpc64__ */
|
||||
|
||||
/*
|
||||
|
||||
@@ -110,7 +110,9 @@ struct kvmppc_host_state {
|
||||
u8 ptid;
|
||||
struct kvm_vcpu *kvm_vcpu;
|
||||
struct kvmppc_vcore *kvm_vcore;
|
||||
unsigned long xics_phys;
|
||||
void __iomem *xics_phys;
|
||||
void __iomem *xive_tima_phys;
|
||||
void __iomem *xive_tima_virt;
|
||||
u32 saved_xirr;
|
||||
u64 dabr;
|
||||
u64 host_mmcr[7]; /* MMCR 0,1,A, SIAR, SDAR, MMCR2, SIER */
|
||||
|
||||
@@ -210,6 +210,12 @@ struct kvmppc_spapr_tce_table {
|
||||
/* XICS components, defined in book3s_xics.c */
|
||||
struct kvmppc_xics;
|
||||
struct kvmppc_icp;
|
||||
extern struct kvm_device_ops kvm_xics_ops;
|
||||
|
||||
/* XIVE components, defined in book3s_xive.c */
|
||||
struct kvmppc_xive;
|
||||
struct kvmppc_xive_vcpu;
|
||||
extern struct kvm_device_ops kvm_xive_ops;
|
||||
|
||||
struct kvmppc_passthru_irqmap;
|
||||
|
||||
@@ -298,6 +304,7 @@ struct kvm_arch {
|
||||
#endif
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
struct kvmppc_xics *xics;
|
||||
struct kvmppc_xive *xive;
|
||||
struct kvmppc_passthru_irqmap *pimap;
|
||||
#endif
|
||||
struct kvmppc_ops *kvm_ops;
|
||||
@@ -427,7 +434,7 @@ struct kvmppc_passthru_irqmap {
|
||||
|
||||
#define KVMPPC_IRQ_DEFAULT 0
|
||||
#define KVMPPC_IRQ_MPIC 1
|
||||
#define KVMPPC_IRQ_XICS 2
|
||||
#define KVMPPC_IRQ_XICS 2 /* Includes a XIVE option */
|
||||
|
||||
#define MMIO_HPTE_CACHE_SIZE 4
|
||||
|
||||
@@ -454,6 +461,21 @@ struct mmio_hpte_cache {
|
||||
|
||||
struct openpic;
|
||||
|
||||
/* W0 and W1 of a XIVE thread management context */
|
||||
union xive_tma_w01 {
|
||||
struct {
|
||||
u8 nsr;
|
||||
u8 cppr;
|
||||
u8 ipb;
|
||||
u8 lsmfb;
|
||||
u8 ack;
|
||||
u8 inc;
|
||||
u8 age;
|
||||
u8 pipr;
|
||||
};
|
||||
__be64 w01;
|
||||
};
|
||||
|
||||
struct kvm_vcpu_arch {
|
||||
ulong host_stack;
|
||||
u32 host_pid;
|
||||
@@ -714,6 +736,10 @@ struct kvm_vcpu_arch {
|
||||
struct openpic *mpic; /* KVM_IRQ_MPIC */
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
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 ? */
|
||||
union xive_tma_w01 xive_saved_state; /* W0..1 of XIVE thread state */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
|
||||
@@ -240,6 +240,7 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq);
|
||||
extern int kvm_vm_ioctl_rtas_define_token(struct kvm *kvm, void __user *argp);
|
||||
extern int kvmppc_rtas_hcall(struct kvm_vcpu *vcpu);
|
||||
extern void kvmppc_rtas_tokens_free(struct kvm *kvm);
|
||||
|
||||
extern int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server,
|
||||
u32 priority);
|
||||
extern int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server,
|
||||
@@ -425,7 +426,15 @@ struct openpic;
|
||||
extern void kvm_cma_reserve(void) __init;
|
||||
static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
|
||||
{
|
||||
paca[cpu].kvm_hstate.xics_phys = addr;
|
||||
paca[cpu].kvm_hstate.xics_phys = (void __iomem *)addr;
|
||||
}
|
||||
|
||||
static inline void kvmppc_set_xive_tima(int cpu,
|
||||
unsigned long phys_addr,
|
||||
void __iomem *virt_addr)
|
||||
{
|
||||
paca[cpu].kvm_hstate.xive_tima_phys = (void __iomem *)phys_addr;
|
||||
paca[cpu].kvm_hstate.xive_tima_virt = virt_addr;
|
||||
}
|
||||
|
||||
static inline u32 kvmppc_get_xics_latch(void)
|
||||
@@ -458,6 +467,11 @@ static inline void __init kvm_cma_reserve(void)
|
||||
static inline void kvmppc_set_xics_phys(int cpu, unsigned long addr)
|
||||
{}
|
||||
|
||||
static inline void kvmppc_set_xive_tima(int cpu,
|
||||
unsigned long phys_addr,
|
||||
void __iomem *virt_addr)
|
||||
{}
|
||||
|
||||
static inline u32 kvmppc_get_xics_latch(void)
|
||||
{
|
||||
return 0;
|
||||
@@ -494,8 +508,6 @@ extern void kvmppc_free_host_rm_ops(void);
|
||||
extern void kvmppc_free_pimap(struct kvm *kvm);
|
||||
extern int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall);
|
||||
extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
|
||||
extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu, unsigned long server);
|
||||
extern int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args);
|
||||
extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd);
|
||||
extern u64 kvmppc_xics_get_icp(struct kvm_vcpu *vcpu);
|
||||
extern int kvmppc_xics_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
|
||||
@@ -510,6 +522,10 @@ extern long kvmppc_deliver_irq_passthru(struct kvm_vcpu *vcpu, __be32 xirr,
|
||||
struct kvmppc_irq_map *irq_map,
|
||||
struct kvmppc_passthru_irqmap *pimap,
|
||||
bool *again);
|
||||
|
||||
extern int kvmppc_xics_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
|
||||
int level, bool line_status);
|
||||
|
||||
extern int h_ipi_redirect;
|
||||
#else
|
||||
static inline struct kvmppc_passthru_irqmap *kvmppc_get_passthru_irqmap(
|
||||
@@ -523,16 +539,64 @@ static inline int kvmppc_xics_rm_complete(struct kvm_vcpu *vcpu, u32 hcall)
|
||||
static inline int kvmppc_xics_enabled(struct kvm_vcpu *vcpu)
|
||||
{ return 0; }
|
||||
static inline void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu) { }
|
||||
static inline int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu,
|
||||
unsigned long server)
|
||||
{ return -EINVAL; }
|
||||
static inline int kvm_vm_ioctl_xics_irq(struct kvm *kvm,
|
||||
struct kvm_irq_level *args)
|
||||
{ return -ENOTTY; }
|
||||
static inline int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd)
|
||||
{ return 0; }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KVM_XIVE
|
||||
/*
|
||||
* Below the first "xive" is the "eXternal Interrupt Virtualization Engine"
|
||||
* ie. P9 new interrupt controller, while the second "xive" is the legacy
|
||||
* "eXternal Interrupt Vector Entry" which is the configuration of an
|
||||
* interrupt on the "xics" interrupt controller on P8 and earlier. Those
|
||||
* two function consume or produce a legacy "XIVE" state from the
|
||||
* new "XIVE" interrupt controller.
|
||||
*/
|
||||
extern int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server,
|
||||
u32 priority);
|
||||
extern int kvmppc_xive_get_xive(struct kvm *kvm, u32 irq, u32 *server,
|
||||
u32 *priority);
|
||||
extern int kvmppc_xive_int_on(struct kvm *kvm, u32 irq);
|
||||
extern int kvmppc_xive_int_off(struct kvm *kvm, u32 irq);
|
||||
extern void kvmppc_xive_init_module(void);
|
||||
extern void kvmppc_xive_exit_module(void);
|
||||
|
||||
extern int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
|
||||
struct kvm_vcpu *vcpu, u32 cpu);
|
||||
extern void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu);
|
||||
extern int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,
|
||||
struct irq_desc *host_desc);
|
||||
extern int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,
|
||||
struct irq_desc *host_desc);
|
||||
extern u64 kvmppc_xive_get_icp(struct kvm_vcpu *vcpu);
|
||||
extern int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval);
|
||||
|
||||
extern int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
|
||||
int level, bool line_status);
|
||||
#else
|
||||
static inline int kvmppc_xive_set_xive(struct kvm *kvm, u32 irq, u32 server,
|
||||
u32 priority) { return -1; }
|
||||
static inline int kvmppc_xive_get_xive(struct kvm *kvm, u32 irq, u32 *server,
|
||||
u32 *priority) { return -1; }
|
||||
static inline int kvmppc_xive_int_on(struct kvm *kvm, u32 irq) { return -1; }
|
||||
static inline int kvmppc_xive_int_off(struct kvm *kvm, u32 irq) { return -1; }
|
||||
static inline void kvmppc_xive_init_module(void) { }
|
||||
static inline void kvmppc_xive_exit_module(void) { }
|
||||
|
||||
static inline int kvmppc_xive_connect_vcpu(struct kvm_device *dev,
|
||||
struct kvm_vcpu *vcpu, u32 cpu) { return -EBUSY; }
|
||||
static inline void kvmppc_xive_cleanup_vcpu(struct kvm_vcpu *vcpu) { }
|
||||
static inline int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq,
|
||||
struct irq_desc *host_desc) { return -ENODEV; }
|
||||
static inline int kvmppc_xive_clr_mapped(struct kvm *kvm, unsigned long guest_irq,
|
||||
struct irq_desc *host_desc) { return -ENODEV; }
|
||||
static inline u64 kvmppc_xive_get_icp(struct kvm_vcpu *vcpu) { return 0; }
|
||||
static inline int kvmppc_xive_set_icp(struct kvm_vcpu *vcpu, u64 icpval) { return -ENOENT; }
|
||||
|
||||
static inline int kvmppc_xive_set_irq(struct kvm *kvm, int irq_source_id, u32 irq,
|
||||
int level, bool line_status) { return -ENODEV; }
|
||||
#endif /* CONFIG_KVM_XIVE */
|
||||
|
||||
/*
|
||||
* Prototypes for functions called only from assembler code.
|
||||
* Having prototypes reduces sparse errors.
|
||||
@@ -570,6 +634,8 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
|
||||
long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
|
||||
unsigned long slb_v, unsigned int status, bool data);
|
||||
unsigned long kvmppc_rm_h_xirr(struct kvm_vcpu *vcpu);
|
||||
unsigned long kvmppc_rm_h_xirr_x(struct kvm_vcpu *vcpu);
|
||||
unsigned long kvmppc_rm_h_ipoll(struct kvm_vcpu *vcpu, unsigned long server);
|
||||
int kvmppc_rm_h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
|
||||
unsigned long mfrr);
|
||||
int kvmppc_rm_h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr);
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#define OPAL_I2C_ARBT_LOST -22
|
||||
#define OPAL_I2C_NACK_RCVD -23
|
||||
#define OPAL_I2C_STOP_ERR -24
|
||||
#define OPAL_XIVE_PROVISIONING -31
|
||||
#define OPAL_XIVE_FREE_ACTIVE -32
|
||||
|
||||
/* API Tokens (in r0) */
|
||||
#define OPAL_INVALID_CALL -1
|
||||
@@ -168,7 +170,24 @@
|
||||
#define OPAL_INT_SET_MFRR 125
|
||||
#define OPAL_PCI_TCE_KILL 126
|
||||
#define OPAL_NMMU_SET_PTCR 127
|
||||
#define OPAL_LAST 127
|
||||
#define OPAL_XIVE_RESET 128
|
||||
#define OPAL_XIVE_GET_IRQ_INFO 129
|
||||
#define OPAL_XIVE_GET_IRQ_CONFIG 130
|
||||
#define OPAL_XIVE_SET_IRQ_CONFIG 131
|
||||
#define OPAL_XIVE_GET_QUEUE_INFO 132
|
||||
#define OPAL_XIVE_SET_QUEUE_INFO 133
|
||||
#define OPAL_XIVE_DONATE_PAGE 134
|
||||
#define OPAL_XIVE_ALLOCATE_VP_BLOCK 135
|
||||
#define OPAL_XIVE_FREE_VP_BLOCK 136
|
||||
#define OPAL_XIVE_GET_VP_INFO 137
|
||||
#define OPAL_XIVE_SET_VP_INFO 138
|
||||
#define OPAL_XIVE_ALLOCATE_IRQ 139
|
||||
#define OPAL_XIVE_FREE_IRQ 140
|
||||
#define OPAL_XIVE_SYNC 141
|
||||
#define OPAL_XIVE_DUMP 142
|
||||
#define OPAL_XIVE_RESERVED3 143
|
||||
#define OPAL_XIVE_RESERVED4 144
|
||||
#define OPAL_LAST 144
|
||||
|
||||
/* Device tree flags */
|
||||
|
||||
@@ -928,6 +947,59 @@ enum {
|
||||
OPAL_PCI_TCE_KILL_ALL,
|
||||
};
|
||||
|
||||
/* The xive operation mode indicates the active "API" and
|
||||
* corresponds to the "mode" parameter of the opal_xive_reset()
|
||||
* call
|
||||
*/
|
||||
enum {
|
||||
OPAL_XIVE_MODE_EMU = 0,
|
||||
OPAL_XIVE_MODE_EXPL = 1,
|
||||
};
|
||||
|
||||
/* Flags for OPAL_XIVE_GET_IRQ_INFO */
|
||||
enum {
|
||||
OPAL_XIVE_IRQ_TRIGGER_PAGE = 0x00000001,
|
||||
OPAL_XIVE_IRQ_STORE_EOI = 0x00000002,
|
||||
OPAL_XIVE_IRQ_LSI = 0x00000004,
|
||||
OPAL_XIVE_IRQ_SHIFT_BUG = 0x00000008,
|
||||
OPAL_XIVE_IRQ_MASK_VIA_FW = 0x00000010,
|
||||
OPAL_XIVE_IRQ_EOI_VIA_FW = 0x00000020,
|
||||
};
|
||||
|
||||
/* Flags for OPAL_XIVE_GET/SET_QUEUE_INFO */
|
||||
enum {
|
||||
OPAL_XIVE_EQ_ENABLED = 0x00000001,
|
||||
OPAL_XIVE_EQ_ALWAYS_NOTIFY = 0x00000002,
|
||||
OPAL_XIVE_EQ_ESCALATE = 0x00000004,
|
||||
};
|
||||
|
||||
/* Flags for OPAL_XIVE_GET/SET_VP_INFO */
|
||||
enum {
|
||||
OPAL_XIVE_VP_ENABLED = 0x00000001,
|
||||
};
|
||||
|
||||
/* "Any chip" replacement for chip ID for allocation functions */
|
||||
enum {
|
||||
OPAL_XIVE_ANY_CHIP = 0xffffffff,
|
||||
};
|
||||
|
||||
/* Xive sync options */
|
||||
enum {
|
||||
/* This bits are cumulative, arg is a girq */
|
||||
XIVE_SYNC_EAS = 0x00000001, /* Sync irq source */
|
||||
XIVE_SYNC_QUEUE = 0x00000002, /* Sync irq target */
|
||||
};
|
||||
|
||||
/* Dump options */
|
||||
enum {
|
||||
XIVE_DUMP_TM_HYP = 0,
|
||||
XIVE_DUMP_TM_POOL = 1,
|
||||
XIVE_DUMP_TM_OS = 2,
|
||||
XIVE_DUMP_TM_USER = 3,
|
||||
XIVE_DUMP_VP = 4,
|
||||
XIVE_DUMP_EMU_STATE = 5,
|
||||
};
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __OPAL_API_H */
|
||||
|
||||
@@ -226,6 +226,42 @@ int64_t opal_pci_tce_kill(uint64_t phb_id, uint32_t kill_type,
|
||||
uint32_t pe_num, uint32_t tce_size,
|
||||
uint64_t dma_addr, uint32_t npages);
|
||||
int64_t opal_nmmu_set_ptcr(uint64_t chip_id, uint64_t ptcr);
|
||||
int64_t opal_xive_reset(uint64_t version);
|
||||
int64_t opal_xive_get_irq_info(uint32_t girq,
|
||||
__be64 *out_flags,
|
||||
__be64 *out_eoi_page,
|
||||
__be64 *out_trig_page,
|
||||
__be32 *out_esb_shift,
|
||||
__be32 *out_src_chip);
|
||||
int64_t opal_xive_get_irq_config(uint32_t girq, __be64 *out_vp,
|
||||
uint8_t *out_prio, __be32 *out_lirq);
|
||||
int64_t opal_xive_set_irq_config(uint32_t girq, uint64_t vp, uint8_t prio,
|
||||
uint32_t lirq);
|
||||
int64_t opal_xive_get_queue_info(uint64_t vp, uint32_t prio,
|
||||
__be64 *out_qpage,
|
||||
__be64 *out_qsize,
|
||||
__be64 *out_qeoi_page,
|
||||
__be32 *out_escalate_irq,
|
||||
__be64 *out_qflags);
|
||||
int64_t opal_xive_set_queue_info(uint64_t vp, uint32_t prio,
|
||||
uint64_t qpage,
|
||||
uint64_t qsize,
|
||||
uint64_t qflags);
|
||||
int64_t opal_xive_donate_page(uint32_t chip_id, uint64_t addr);
|
||||
int64_t opal_xive_alloc_vp_block(uint32_t alloc_order);
|
||||
int64_t opal_xive_free_vp_block(uint64_t vp);
|
||||
int64_t opal_xive_get_vp_info(uint64_t vp,
|
||||
__be64 *out_flags,
|
||||
__be64 *out_cam_value,
|
||||
__be64 *out_report_cl_pair,
|
||||
__be32 *out_chip_id);
|
||||
int64_t opal_xive_set_vp_info(uint64_t vp,
|
||||
uint64_t flags,
|
||||
uint64_t report_cl_pair);
|
||||
int64_t opal_xive_allocate_irq(uint32_t chip_id);
|
||||
int64_t opal_xive_free_irq(uint32_t girq);
|
||||
int64_t opal_xive_sync(uint32_t type, uint32_t id);
|
||||
int64_t opal_xive_dump(uint32_t type, uint32_t id);
|
||||
|
||||
/* Internal functions */
|
||||
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
|
||||
|
||||
@@ -365,6 +365,7 @@
|
||||
#define LPCR_MER_SH 11
|
||||
#define LPCR_GTSE ASM_CONST(0x0000000000000400) /* Guest Translation Shootdown Enable */
|
||||
#define LPCR_TC ASM_CONST(0x0000000000000200) /* Translation control */
|
||||
#define LPCR_HEIC ASM_CONST(0x0000000000000010) /* Hypervisor External Interrupt Control */
|
||||
#define LPCR_LPES 0x0000000c
|
||||
#define LPCR_LPES0 ASM_CONST(0x0000000000000008) /* LPAR Env selector 0 */
|
||||
#define LPCR_LPES1 ASM_CONST(0x0000000000000004) /* LPAR Env selector 1 */
|
||||
|
||||
@@ -44,6 +44,7 @@ struct smp_ops_t {
|
||||
#endif
|
||||
void (*probe)(void);
|
||||
int (*kick_cpu)(int nr);
|
||||
int (*prepare_cpu)(int nr);
|
||||
void (*setup_cpu)(int nr);
|
||||
void (*bringup_done)(void);
|
||||
void (*take_timebase)(void);
|
||||
@@ -61,7 +62,6 @@ extern void smp_generic_take_timebase(void);
|
||||
DECLARE_PER_CPU(unsigned int, cpu_pvr);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
extern void migrate_irqs(void);
|
||||
int generic_cpu_disable(void);
|
||||
void generic_cpu_die(unsigned int cpu);
|
||||
void generic_set_cpu_dead(unsigned int cpu);
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2016,2017 IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#ifndef _ASM_POWERPC_XIVE_REGS_H
|
||||
#define _ASM_POWERPC_XIVE_REGS_H
|
||||
|
||||
/*
|
||||
* Thread Management (aka "TM") registers
|
||||
*/
|
||||
|
||||
/* TM register offsets */
|
||||
#define TM_QW0_USER 0x000 /* All rings */
|
||||
#define TM_QW1_OS 0x010 /* Ring 0..2 */
|
||||
#define TM_QW2_HV_POOL 0x020 /* Ring 0..1 */
|
||||
#define TM_QW3_HV_PHYS 0x030 /* Ring 0..1 */
|
||||
|
||||
/* Byte offsets inside a QW QW0 QW1 QW2 QW3 */
|
||||
#define TM_NSR 0x0 /* + + - + */
|
||||
#define TM_CPPR 0x1 /* - + - + */
|
||||
#define TM_IPB 0x2 /* - + + + */
|
||||
#define TM_LSMFB 0x3 /* - + + + */
|
||||
#define TM_ACK_CNT 0x4 /* - + - - */
|
||||
#define TM_INC 0x5 /* - + - + */
|
||||
#define TM_AGE 0x6 /* - + - + */
|
||||
#define TM_PIPR 0x7 /* - + - + */
|
||||
|
||||
#define TM_WORD0 0x0
|
||||
#define TM_WORD1 0x4
|
||||
|
||||
/*
|
||||
* QW word 2 contains the valid bit at the top and other fields
|
||||
* depending on the QW.
|
||||
*/
|
||||
#define TM_WORD2 0x8
|
||||
#define TM_QW0W2_VU PPC_BIT32(0)
|
||||
#define TM_QW0W2_LOGIC_SERV PPC_BITMASK32(1,31) // XX 2,31 ?
|
||||
#define TM_QW1W2_VO PPC_BIT32(0)
|
||||
#define TM_QW1W2_OS_CAM PPC_BITMASK32(8,31)
|
||||
#define TM_QW2W2_VP PPC_BIT32(0)
|
||||
#define TM_QW2W2_POOL_CAM PPC_BITMASK32(8,31)
|
||||
#define TM_QW3W2_VT PPC_BIT32(0)
|
||||
#define TM_QW3W2_LP PPC_BIT32(6)
|
||||
#define TM_QW3W2_LE PPC_BIT32(7)
|
||||
#define TM_QW3W2_T PPC_BIT32(31)
|
||||
|
||||
/*
|
||||
* In addition to normal loads to "peek" and writes (only when invalid)
|
||||
* using 4 and 8 bytes accesses, the above registers support these
|
||||
* "special" byte operations:
|
||||
*
|
||||
* - Byte load from QW0[NSR] - User level NSR (EBB)
|
||||
* - Byte store to QW0[NSR] - User level NSR (EBB)
|
||||
* - Byte load/store to QW1[CPPR] and QW3[CPPR] - CPPR access
|
||||
* - Byte load from QW3[TM_WORD2] - Read VT||00000||LP||LE on thrd 0
|
||||
* otherwise VT||0000000
|
||||
* - Byte store to QW3[TM_WORD2] - Set VT bit (and LP/LE if present)
|
||||
*
|
||||
* Then we have all these "special" CI ops at these offset that trigger
|
||||
* all sorts of side effects:
|
||||
*/
|
||||
#define TM_SPC_ACK_EBB 0x800 /* Load8 ack EBB to reg*/
|
||||
#define TM_SPC_ACK_OS_REG 0x810 /* Load16 ack OS irq to reg */
|
||||
#define TM_SPC_PUSH_USR_CTX 0x808 /* Store32 Push/Validate user context */
|
||||
#define TM_SPC_PULL_USR_CTX 0x808 /* Load32 Pull/Invalidate user context */
|
||||
#define TM_SPC_SET_OS_PENDING 0x812 /* Store8 Set OS irq pending bit */
|
||||
#define TM_SPC_PULL_OS_CTX 0x818 /* Load32/Load64 Pull/Invalidate OS context to reg */
|
||||
#define TM_SPC_PULL_POOL_CTX 0x828 /* Load32/Load64 Pull/Invalidate Pool context to reg*/
|
||||
#define TM_SPC_ACK_HV_REG 0x830 /* Load16 ack HV irq to reg */
|
||||
#define TM_SPC_PULL_USR_CTX_OL 0xc08 /* Store8 Pull/Inval usr ctx to odd line */
|
||||
#define TM_SPC_ACK_OS_EL 0xc10 /* Store8 ack OS irq to even line */
|
||||
#define TM_SPC_ACK_HV_POOL_EL 0xc20 /* Store8 ack HV evt pool to even line */
|
||||
#define TM_SPC_ACK_HV_EL 0xc30 /* Store8 ack HV irq to even line */
|
||||
/* XXX more... */
|
||||
|
||||
/* NSR fields for the various QW ack types */
|
||||
#define TM_QW0_NSR_EB PPC_BIT8(0)
|
||||
#define TM_QW1_NSR_EO PPC_BIT8(0)
|
||||
#define TM_QW3_NSR_HE PPC_BITMASK8(0,1)
|
||||
#define TM_QW3_NSR_HE_NONE 0
|
||||
#define TM_QW3_NSR_HE_POOL 1
|
||||
#define TM_QW3_NSR_HE_PHYS 2
|
||||
#define TM_QW3_NSR_HE_LSI 3
|
||||
#define TM_QW3_NSR_I PPC_BIT8(2)
|
||||
#define TM_QW3_NSR_GRP_LVL PPC_BIT8(3,7)
|
||||
|
||||
/* Utilities to manipulate these (originaly from OPAL) */
|
||||
#define MASK_TO_LSH(m) (__builtin_ffsl(m) - 1)
|
||||
#define GETFIELD(m, v) (((v) & (m)) >> MASK_TO_LSH(m))
|
||||
#define SETFIELD(m, v, val) \
|
||||
(((v) & ~(m)) | ((((typeof(v))(val)) << MASK_TO_LSH(m)) & (m)))
|
||||
|
||||
#endif /* _ASM_POWERPC_XIVE_REGS_H */
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2016,2017 IBM Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
#ifndef _ASM_POWERPC_XIVE_H
|
||||
#define _ASM_POWERPC_XIVE_H
|
||||
|
||||
#define XIVE_INVALID_VP 0xffffffff
|
||||
|
||||
#ifdef CONFIG_PPC_XIVE
|
||||
|
||||
/*
|
||||
* Thread Interrupt Management Area (TIMA)
|
||||
*
|
||||
* This is a global MMIO region divided in 4 pages of varying access
|
||||
* permissions, providing access to per-cpu interrupt management
|
||||
* functions. It always identifies the CPU doing the access based
|
||||
* on the PowerBus initiator ID, thus we always access via the
|
||||
* same offset regardless of where the code is executing
|
||||
*/
|
||||
extern void __iomem *xive_tima;
|
||||
|
||||
/*
|
||||
* Offset in the TM area of our current execution level (provided by
|
||||
* the backend)
|
||||
*/
|
||||
extern u32 xive_tima_offset;
|
||||
|
||||
/*
|
||||
* Per-irq data (irq_get_handler_data for normal IRQs), IPIs
|
||||
* have it stored in the xive_cpu structure. We also cache
|
||||
* for normal interrupts the current target CPU.
|
||||
*
|
||||
* This structure is setup by the backend for each interrupt.
|
||||
*/
|
||||
struct xive_irq_data {
|
||||
u64 flags;
|
||||
u64 eoi_page;
|
||||
void __iomem *eoi_mmio;
|
||||
u64 trig_page;
|
||||
void __iomem *trig_mmio;
|
||||
u32 esb_shift;
|
||||
int src_chip;
|
||||
|
||||
/* Setup/used by frontend */
|
||||
int target;
|
||||
bool saved_p;
|
||||
};
|
||||
#define XIVE_IRQ_FLAG_STORE_EOI 0x01
|
||||
#define XIVE_IRQ_FLAG_LSI 0x02
|
||||
#define XIVE_IRQ_FLAG_SHIFT_BUG 0x04
|
||||
#define XIVE_IRQ_FLAG_MASK_FW 0x08
|
||||
#define XIVE_IRQ_FLAG_EOI_FW 0x10
|
||||
|
||||
#define XIVE_INVALID_CHIP_ID -1
|
||||
|
||||
/* A queue tracking structure in a CPU */
|
||||
struct xive_q {
|
||||
__be32 *qpage;
|
||||
u32 msk;
|
||||
u32 idx;
|
||||
u32 toggle;
|
||||
u64 eoi_phys;
|
||||
u32 esc_irq;
|
||||
atomic_t count;
|
||||
atomic_t pending_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* "magic" Event State Buffer (ESB) MMIO offsets.
|
||||
*
|
||||
* Each interrupt source has a 2-bit state machine called ESB
|
||||
* which can be controlled by MMIO. It's made of 2 bits, P and
|
||||
* Q. P indicates that an interrupt is pending (has been sent
|
||||
* to a queue and is waiting for an EOI). Q indicates that the
|
||||
* interrupt has been triggered while pending.
|
||||
*
|
||||
* This acts as a coalescing mechanism in order to guarantee
|
||||
* that a given interrupt only occurs at most once in a queue.
|
||||
*
|
||||
* When doing an EOI, the Q bit will indicate if the interrupt
|
||||
* needs to be re-triggered.
|
||||
*
|
||||
* The following offsets into the ESB MMIO allow to read or
|
||||
* manipulate the PQ bits. They must be used with an 8-bytes
|
||||
* load instruction. They all return the previous state of the
|
||||
* interrupt (atomically).
|
||||
*
|
||||
* Additionally, some ESB pages support doing an EOI via a
|
||||
* store at 0 and some ESBs support doing a trigger via a
|
||||
* separate trigger page.
|
||||
*/
|
||||
#define XIVE_ESB_GET 0x800
|
||||
#define XIVE_ESB_SET_PQ_00 0xc00
|
||||
#define XIVE_ESB_SET_PQ_01 0xd00
|
||||
#define XIVE_ESB_SET_PQ_10 0xe00
|
||||
#define XIVE_ESB_SET_PQ_11 0xf00
|
||||
|
||||
#define XIVE_ESB_VAL_P 0x2
|
||||
#define XIVE_ESB_VAL_Q 0x1
|
||||
|
||||
/* Global enable flags for the XIVE support */
|
||||
extern bool __xive_enabled;
|
||||
|
||||
static inline bool xive_enabled(void) { return __xive_enabled; }
|
||||
|
||||
extern bool xive_native_init(void);
|
||||
extern void xive_smp_probe(void);
|
||||
extern int xive_smp_prepare_cpu(unsigned int cpu);
|
||||
extern void xive_smp_setup_cpu(void);
|
||||
extern void xive_smp_disable_cpu(void);
|
||||
extern void xive_kexec_teardown_cpu(int secondary);
|
||||
extern void xive_shutdown(void);
|
||||
extern void xive_flush_interrupt(void);
|
||||
|
||||
/* xmon hook */
|
||||
extern void xmon_xive_do_dump(int cpu);
|
||||
|
||||
/* APIs used by KVM */
|
||||
extern u32 xive_native_default_eq_shift(void);
|
||||
extern u32 xive_native_alloc_vp_block(u32 max_vcpus);
|
||||
extern void xive_native_free_vp_block(u32 vp_base);
|
||||
extern int xive_native_populate_irq_data(u32 hw_irq,
|
||||
struct xive_irq_data *data);
|
||||
extern void xive_cleanup_irq_data(struct xive_irq_data *xd);
|
||||
extern u32 xive_native_alloc_irq(void);
|
||||
extern void xive_native_free_irq(u32 irq);
|
||||
extern int xive_native_configure_irq(u32 hw_irq, u32 target, u8 prio, u32 sw_irq);
|
||||
|
||||
extern int xive_native_configure_queue(u32 vp_id, struct xive_q *q, u8 prio,
|
||||
__be32 *qpage, u32 order, bool can_escalate);
|
||||
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_disable_vp(u32 vp_id);
|
||||
extern int xive_native_get_vp_info(u32 vp_id, u32 *out_cam_id, u32 *out_chip_id);
|
||||
|
||||
#else
|
||||
|
||||
static inline bool xive_enabled(void) { return false; }
|
||||
|
||||
static inline bool xive_native_init(void) { return false; }
|
||||
static inline void xive_smp_probe(void) { }
|
||||
extern inline int xive_smp_prepare_cpu(unsigned int cpu) { return -EINVAL; }
|
||||
static inline void xive_smp_setup_cpu(void) { }
|
||||
static inline void xive_smp_disable_cpu(void) { }
|
||||
static inline void xive_kexec_teardown_cpu(int secondary) { }
|
||||
static inline void xive_shutdown(void) { }
|
||||
static inline void xive_flush_interrupt(void) { }
|
||||
|
||||
static inline u32 xive_native_alloc_vp_block(u32 max_vcpus) { return XIVE_INVALID_VP; }
|
||||
static inline void xive_native_free_vp_block(u32 vp_base) { }
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_POWERPC_XIVE_H */
|
||||
@@ -29,5 +29,7 @@ static inline void xmon_register_spus(struct list_head *list) { };
|
||||
extern int cpus_are_in_xmon(void);
|
||||
#endif
|
||||
|
||||
extern void xmon_printf(const char *format, ...);
|
||||
|
||||
#endif /* __KERNEL __ */
|
||||
#endif /* __ASM_POWERPC_XMON_H */
|
||||
|
||||
@@ -630,6 +630,8 @@ int main(void)
|
||||
HSTATE_FIELD(HSTATE_KVM_VCPU, kvm_vcpu);
|
||||
HSTATE_FIELD(HSTATE_KVM_VCORE, kvm_vcore);
|
||||
HSTATE_FIELD(HSTATE_XICS_PHYS, xics_phys);
|
||||
HSTATE_FIELD(HSTATE_XIVE_TIMA_PHYS, xive_tima_phys);
|
||||
HSTATE_FIELD(HSTATE_XIVE_TIMA_VIRT, xive_tima_virt);
|
||||
HSTATE_FIELD(HSTATE_SAVED_XIRR, saved_xirr);
|
||||
HSTATE_FIELD(HSTATE_HOST_IPI, host_ipi);
|
||||
HSTATE_FIELD(HSTATE_PTID, ptid);
|
||||
@@ -715,6 +717,14 @@ int main(void)
|
||||
OFFSET(VCPU_HOST_MAS6, kvm_vcpu, arch.host_mas6);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
DEFINE(VCPU_XIVE_SAVED_STATE, offsetof(struct kvm_vcpu,
|
||||
arch.xive_saved_state));
|
||||
DEFINE(VCPU_XIVE_CAM_WORD, offsetof(struct kvm_vcpu,
|
||||
arch.xive_cam_word));
|
||||
DEFINE(VCPU_XIVE_PUSHED, offsetof(struct kvm_vcpu, arch.xive_pushed));
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KVM_EXIT_TIMING
|
||||
OFFSET(VCPU_TIMING_EXIT_TBU, kvm_vcpu, arch.timing_exit.tv32.tbu);
|
||||
OFFSET(VCPU_TIMING_EXIT_TBL, kvm_vcpu, arch.timing_exit.tv32.tbl);
|
||||
|
||||
@@ -29,6 +29,7 @@ _GLOBAL(__setup_cpu_power7)
|
||||
li r0,0
|
||||
mtspr SPRN_LPID,r0
|
||||
mfspr r3,SPRN_LPCR
|
||||
li r4,(LPCR_LPES1 >> LPCR_LPES_SH)
|
||||
bl __init_LPCR
|
||||
bl __init_tlb_power7
|
||||
mtlr r11
|
||||
@@ -42,6 +43,7 @@ _GLOBAL(__restore_cpu_power7)
|
||||
li r0,0
|
||||
mtspr SPRN_LPID,r0
|
||||
mfspr r3,SPRN_LPCR
|
||||
li r4,(LPCR_LPES1 >> LPCR_LPES_SH)
|
||||
bl __init_LPCR
|
||||
bl __init_tlb_power7
|
||||
mtlr r11
|
||||
@@ -59,6 +61,7 @@ _GLOBAL(__setup_cpu_power8)
|
||||
mtspr SPRN_LPID,r0
|
||||
mfspr r3,SPRN_LPCR
|
||||
ori r3, r3, LPCR_PECEDH
|
||||
li r4,0 /* LPES = 0 */
|
||||
bl __init_LPCR
|
||||
bl __init_HFSCR
|
||||
bl __init_tlb_power8
|
||||
@@ -80,6 +83,7 @@ _GLOBAL(__restore_cpu_power8)
|
||||
mtspr SPRN_LPID,r0
|
||||
mfspr r3,SPRN_LPCR
|
||||
ori r3, r3, LPCR_PECEDH
|
||||
li r4,0 /* LPES = 0 */
|
||||
bl __init_LPCR
|
||||
bl __init_HFSCR
|
||||
bl __init_tlb_power8
|
||||
@@ -99,10 +103,11 @@ _GLOBAL(__setup_cpu_power9)
|
||||
mtspr SPRN_PSSCR,r0
|
||||
mtspr SPRN_LPID,r0
|
||||
mfspr r3,SPRN_LPCR
|
||||
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE)
|
||||
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC)
|
||||
or r3, r3, r4
|
||||
LOAD_REG_IMMEDIATE(r4, LPCR_UPRT | LPCR_HR)
|
||||
andc r3, r3, r4
|
||||
li r4,0 /* LPES = 0 */
|
||||
bl __init_LPCR
|
||||
bl __init_HFSCR
|
||||
bl __init_tlb_power9
|
||||
@@ -122,10 +127,11 @@ _GLOBAL(__restore_cpu_power9)
|
||||
mtspr SPRN_PSSCR,r0
|
||||
mtspr SPRN_LPID,r0
|
||||
mfspr r3,SPRN_LPCR
|
||||
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE)
|
||||
LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE | LPCR_HEIC)
|
||||
or r3, r3, r4
|
||||
LOAD_REG_IMMEDIATE(r4, LPCR_UPRT | LPCR_HR)
|
||||
andc r3, r3, r4
|
||||
li r4,0 /* LPES = 0 */
|
||||
bl __init_LPCR
|
||||
bl __init_HFSCR
|
||||
bl __init_tlb_power9
|
||||
@@ -146,7 +152,7 @@ __init_hvmode_206:
|
||||
|
||||
__init_LPCR:
|
||||
/* Setup a sane LPCR:
|
||||
* Called with initial LPCR in R3
|
||||
* Called with initial LPCR in R3 and desired LPES 2-bit value in R4
|
||||
*
|
||||
* LPES = 0b01 (HSRR0/1 used for 0x500)
|
||||
* PECE = 0b111
|
||||
@@ -157,8 +163,7 @@ __init_LPCR:
|
||||
*
|
||||
* Other bits untouched for now
|
||||
*/
|
||||
li r5,1
|
||||
rldimi r3,r5, LPCR_LPES_SH, 64-LPCR_LPES_SH-2
|
||||
rldimi r3,r4, LPCR_LPES_SH, 64-LPCR_LPES_SH-2
|
||||
ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2)
|
||||
li r5,4
|
||||
rldimi r3,r5, LPCR_DPFD_SH, 64-LPCR_DPFD_SH-3
|
||||
|
||||
@@ -442,46 +442,6 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
|
||||
return sum;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void migrate_irqs(void)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
unsigned int irq;
|
||||
static int warned;
|
||||
cpumask_var_t mask;
|
||||
const struct cpumask *map = cpu_online_mask;
|
||||
|
||||
alloc_cpumask_var(&mask, GFP_KERNEL);
|
||||
|
||||
for_each_irq_desc(irq, desc) {
|
||||
struct irq_data *data;
|
||||
struct irq_chip *chip;
|
||||
|
||||
data = irq_desc_get_irq_data(desc);
|
||||
if (irqd_is_per_cpu(data))
|
||||
continue;
|
||||
|
||||
chip = irq_data_get_irq_chip(data);
|
||||
|
||||
cpumask_and(mask, irq_data_get_affinity_mask(data), map);
|
||||
if (cpumask_any(mask) >= nr_cpu_ids) {
|
||||
pr_warn("Breaking affinity for irq %i\n", irq);
|
||||
cpumask_copy(mask, map);
|
||||
}
|
||||
if (chip->irq_set_affinity)
|
||||
chip->irq_set_affinity(data, mask, true);
|
||||
else if (desc->action && !(warned++))
|
||||
pr_err("Cannot set affinity for irq %i\n", irq);
|
||||
}
|
||||
|
||||
free_cpumask_var(mask);
|
||||
|
||||
local_irq_enable();
|
||||
mdelay(1);
|
||||
local_irq_disable();
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void check_stack_overflow(void)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_STACKOVERFLOW
|
||||
|
||||
@@ -439,7 +439,14 @@ int generic_cpu_disable(void)
|
||||
#ifdef CONFIG_PPC64
|
||||
vdso_data->processorCount--;
|
||||
#endif
|
||||
migrate_irqs();
|
||||
/* Update affinity of all IRQs previously aimed at this CPU */
|
||||
irq_migrate_all_off_this_cpu();
|
||||
|
||||
/* Give the CPU time to drain in-flight ones */
|
||||
local_irq_enable();
|
||||
mdelay(1);
|
||||
local_irq_disable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -521,6 +528,16 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
|
||||
|
||||
cpu_idle_thread_init(cpu, tidle);
|
||||
|
||||
/*
|
||||
* The platform might need to allocate resources prior to bringing
|
||||
* up the CPU
|
||||
*/
|
||||
if (smp_ops->prepare_cpu) {
|
||||
rc = smp_ops->prepare_cpu(cpu);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Make sure callin-map entry is 0 (can be leftover a CPU
|
||||
* hotplug
|
||||
*/
|
||||
|
||||
@@ -197,6 +197,11 @@ config KVM_XICS
|
||||
Specification) interrupt controller architecture used on
|
||||
IBM POWER (pSeries) servers.
|
||||
|
||||
config KVM_XIVE
|
||||
bool
|
||||
default y
|
||||
depends on KVM_XICS && PPC_XIVE_NATIVE && KVM_BOOK3S_HV_POSSIBLE
|
||||
|
||||
source drivers/vhost/Kconfig
|
||||
|
||||
endif # VIRTUALIZATION
|
||||
|
||||
@@ -74,7 +74,7 @@ kvm-hv-y += \
|
||||
book3s_64_mmu_radix.o
|
||||
|
||||
kvm-book3s_64-builtin-xics-objs-$(CONFIG_KVM_XICS) := \
|
||||
book3s_hv_rm_xics.o
|
||||
book3s_hv_rm_xics.o book3s_hv_rm_xive.o
|
||||
|
||||
ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
|
||||
kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \
|
||||
@@ -89,6 +89,8 @@ endif
|
||||
kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
|
||||
book3s_xics.o
|
||||
|
||||
kvm-book3s_64-objs-$(CONFIG_KVM_XIVE) += book3s_xive.o
|
||||
|
||||
kvm-book3s_64-module-objs := \
|
||||
$(common-objs-y) \
|
||||
book3s.o \
|
||||
|
||||
+73
-10
@@ -20,6 +20,10 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/highmem.h>
|
||||
|
||||
#include <asm/reg.h>
|
||||
#include <asm/cputable.h>
|
||||
@@ -31,10 +35,7 @@
|
||||
#include <asm/kvm_book3s.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <asm/xive.h>
|
||||
|
||||
#include "book3s.h"
|
||||
#include "trace.h"
|
||||
@@ -596,11 +597,14 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
|
||||
break;
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
case KVM_REG_PPC_ICP_STATE:
|
||||
if (!vcpu->arch.icp) {
|
||||
if (!vcpu->arch.icp && !vcpu->arch.xive_vcpu) {
|
||||
r = -ENXIO;
|
||||
break;
|
||||
}
|
||||
*val = get_reg_val(id, kvmppc_xics_get_icp(vcpu));
|
||||
if (xive_enabled())
|
||||
*val = get_reg_val(id, kvmppc_xive_get_icp(vcpu));
|
||||
else
|
||||
*val = get_reg_val(id, kvmppc_xics_get_icp(vcpu));
|
||||
break;
|
||||
#endif /* CONFIG_KVM_XICS */
|
||||
case KVM_REG_PPC_FSCR:
|
||||
@@ -666,12 +670,14 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
|
||||
#endif /* CONFIG_VSX */
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
case KVM_REG_PPC_ICP_STATE:
|
||||
if (!vcpu->arch.icp) {
|
||||
if (!vcpu->arch.icp && !vcpu->arch.xive_vcpu) {
|
||||
r = -ENXIO;
|
||||
break;
|
||||
}
|
||||
r = kvmppc_xics_set_icp(vcpu,
|
||||
set_reg_val(id, *val));
|
||||
if (xive_enabled())
|
||||
r = kvmppc_xive_set_icp(vcpu, set_reg_val(id, *val));
|
||||
else
|
||||
r = kvmppc_xics_set_icp(vcpu, set_reg_val(id, *val));
|
||||
break;
|
||||
#endif /* CONFIG_KVM_XICS */
|
||||
case KVM_REG_PPC_FSCR:
|
||||
@@ -942,6 +948,50 @@ int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hcall)
|
||||
return kvm->arch.kvm_ops->hcall_implemented(hcall);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
|
||||
bool line_status)
|
||||
{
|
||||
if (xive_enabled())
|
||||
return kvmppc_xive_set_irq(kvm, irq_source_id, irq, level,
|
||||
line_status);
|
||||
else
|
||||
return kvmppc_xics_set_irq(kvm, irq_source_id, irq, level,
|
||||
line_status);
|
||||
}
|
||||
|
||||
int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry,
|
||||
struct kvm *kvm, int irq_source_id,
|
||||
int level, bool line_status)
|
||||
{
|
||||
return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi,
|
||||
level, line_status);
|
||||
}
|
||||
static int kvmppc_book3s_set_irq(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int irq_source_id, int level,
|
||||
bool line_status)
|
||||
{
|
||||
return kvm_set_irq(kvm, irq_source_id, e->gsi, level, line_status);
|
||||
}
|
||||
|
||||
int kvm_irq_map_gsi(struct kvm *kvm,
|
||||
struct kvm_kernel_irq_routing_entry *entries, int gsi)
|
||||
{
|
||||
entries->gsi = gsi;
|
||||
entries->type = KVM_IRQ_ROUTING_IRQCHIP;
|
||||
entries->set = kvmppc_book3s_set_irq;
|
||||
entries->irqchip.irqchip = 0;
|
||||
entries->irqchip.pin = gsi;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
|
||||
{
|
||||
return pin;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_KVM_XICS */
|
||||
|
||||
static int kvmppc_book3s_init(void)
|
||||
{
|
||||
int r;
|
||||
@@ -952,12 +1002,25 @@ static int kvmppc_book3s_init(void)
|
||||
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
|
||||
r = kvmppc_book3s_init_pr();
|
||||
#endif
|
||||
return r;
|
||||
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
#ifdef CONFIG_KVM_XIVE
|
||||
if (xive_enabled()) {
|
||||
kvmppc_xive_init_module();
|
||||
kvm_register_device_ops(&kvm_xive_ops, KVM_DEV_TYPE_XICS);
|
||||
} else
|
||||
#endif
|
||||
kvm_register_device_ops(&kvm_xics_ops, KVM_DEV_TYPE_XICS);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
static void kvmppc_book3s_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_KVM_XICS
|
||||
if (xive_enabled())
|
||||
kvmppc_xive_exit_module();
|
||||
#endif
|
||||
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
|
||||
kvmppc_book3s_exit_pr();
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,15 @@
|
||||
#include <linux/srcu.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/kvm_irqfd.h>
|
||||
#include <linux/irqbypass.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <asm/reg.h>
|
||||
#include <asm/cputable.h>
|
||||
@@ -58,15 +67,7 @@
|
||||
#include <asm/mmu.h>
|
||||
#include <asm/opal.h>
|
||||
#include <asm/xics.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/kvm_irqfd.h>
|
||||
#include <linux/irqbypass.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/xive.h>
|
||||
|
||||
#include "book3s.h"
|
||||
|
||||
@@ -837,6 +838,10 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
|
||||
case H_IPOLL:
|
||||
case H_XIRR_X:
|
||||
if (kvmppc_xics_enabled(vcpu)) {
|
||||
if (xive_enabled()) {
|
||||
ret = H_NOT_AVAILABLE;
|
||||
return RESUME_GUEST;
|
||||
}
|
||||
ret = kvmppc_xics_hcall(vcpu, req);
|
||||
break;
|
||||
}
|
||||
@@ -2947,8 +2952,12 @@ static int kvmppc_vcpu_run_hv(struct kvm_run *run, struct kvm_vcpu *vcpu)
|
||||
r = kvmppc_book3s_hv_page_fault(run, vcpu,
|
||||
vcpu->arch.fault_dar, vcpu->arch.fault_dsisr);
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
|
||||
} else if (r == RESUME_PASSTHROUGH)
|
||||
r = kvmppc_xics_rm_complete(vcpu, 0);
|
||||
} else if (r == RESUME_PASSTHROUGH) {
|
||||
if (WARN_ON(xive_enabled()))
|
||||
r = H_SUCCESS;
|
||||
else
|
||||
r = kvmppc_xics_rm_complete(vcpu, 0);
|
||||
}
|
||||
} while (is_kvmppc_resume_guest(r));
|
||||
|
||||
out:
|
||||
@@ -3400,10 +3409,20 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
|
||||
/*
|
||||
* On POWER9, VPM0 bit is reserved (VPM0=1 behaviour is assumed)
|
||||
* Set HVICE bit to enable hypervisor virtualization interrupts.
|
||||
* Set HEIC to prevent OS interrupts to go to hypervisor (should
|
||||
* be unnecessary but better safe than sorry in case we re-enable
|
||||
* EE in HV mode with this LPCR still set)
|
||||
*/
|
||||
if (cpu_has_feature(CPU_FTR_ARCH_300)) {
|
||||
lpcr &= ~LPCR_VPM0;
|
||||
lpcr |= LPCR_HVICE;
|
||||
lpcr |= LPCR_HVICE | LPCR_HEIC;
|
||||
|
||||
/*
|
||||
* If xive is enabled, we route 0x500 interrupts directly
|
||||
* to the guest.
|
||||
*/
|
||||
if (xive_enabled())
|
||||
lpcr |= LPCR_LPES;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3533,7 +3552,7 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
|
||||
struct kvmppc_irq_map *irq_map;
|
||||
struct kvmppc_passthru_irqmap *pimap;
|
||||
struct irq_chip *chip;
|
||||
int i;
|
||||
int i, rc = 0;
|
||||
|
||||
if (!kvm_irq_bypass)
|
||||
return 1;
|
||||
@@ -3558,10 +3577,10 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
|
||||
/*
|
||||
* For now, we only support interrupts for which the EOI operation
|
||||
* is an OPAL call followed by a write to XIRR, since that's
|
||||
* what our real-mode EOI code does.
|
||||
* what our real-mode EOI code does, or a XIVE interrupt
|
||||
*/
|
||||
chip = irq_data_get_irq_chip(&desc->irq_data);
|
||||
if (!chip || !is_pnv_opal_msi(chip)) {
|
||||
if (!chip || !(is_pnv_opal_msi(chip) || is_xive_irq(chip))) {
|
||||
pr_warn("kvmppc_set_passthru_irq_hv: Could not assign IRQ map for (%d,%d)\n",
|
||||
host_irq, guest_gsi);
|
||||
mutex_unlock(&kvm->lock);
|
||||
@@ -3603,7 +3622,12 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
|
||||
if (i == pimap->n_mapped)
|
||||
pimap->n_mapped++;
|
||||
|
||||
kvmppc_xics_set_mapped(kvm, guest_gsi, desc->irq_data.hwirq);
|
||||
if (xive_enabled())
|
||||
rc = kvmppc_xive_set_mapped(kvm, guest_gsi, desc);
|
||||
else
|
||||
kvmppc_xics_set_mapped(kvm, guest_gsi, desc->irq_data.hwirq);
|
||||
if (rc)
|
||||
irq_map->r_hwirq = 0;
|
||||
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
||||
@@ -3614,7 +3638,7 @@ static int kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
struct kvmppc_passthru_irqmap *pimap;
|
||||
int i;
|
||||
int i, rc = 0;
|
||||
|
||||
if (!kvm_irq_bypass)
|
||||
return 0;
|
||||
@@ -3639,9 +3663,12 @@ static int kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
kvmppc_xics_clr_mapped(kvm, guest_gsi, pimap->mapped[i].r_hwirq);
|
||||
if (xive_enabled())
|
||||
rc = kvmppc_xive_clr_mapped(kvm, guest_gsi, pimap->mapped[i].desc);
|
||||
else
|
||||
kvmppc_xics_clr_mapped(kvm, guest_gsi, pimap->mapped[i].r_hwirq);
|
||||
|
||||
/* invalidate the entry */
|
||||
/* invalidate the entry (what do do on error from the above ?) */
|
||||
pimap->mapped[i].r_hwirq = 0;
|
||||
|
||||
/*
|
||||
@@ -3650,7 +3677,7 @@ static int kvmppc_clr_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi)
|
||||
*/
|
||||
unlock:
|
||||
mutex_unlock(&kvm->lock);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int kvmppc_irq_bypass_add_producer_hv(struct irq_bypass_consumer *cons,
|
||||
@@ -3928,7 +3955,7 @@ static int kvmppc_book3s_init_hv(void)
|
||||
* indirectly, via OPAL.
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
if (!local_paca->kvm_hstate.xics_phys) {
|
||||
if (!xive_enabled() && !local_paca->kvm_hstate.xics_phys) {
|
||||
struct device_node *np;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "ibm,opal-intc");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user