2013-04-17 20:30:26 +00:00
/*
* Copyright 2012 Michael Ellerman , IBM Corporation .
* Copyright 2012 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_XICS_H
# define _KVM_PPC_BOOK3S_XICS_H
/*
* We use a two - level tree to store interrupt source information .
* There are up to 1024 ICS nodes , each of which can represent
* 1024 sources .
*/
# define KVMPPC_XICS_MAX_ICS_ID 1023
# define KVMPPC_XICS_ICS_SHIFT 10
# define KVMPPC_XICS_IRQ_PER_ICS (1 << KVMPPC_XICS_ICS_SHIFT)
# define KVMPPC_XICS_SRC_MASK (KVMPPC_XICS_IRQ_PER_ICS - 1)
/*
* Interrupt source numbers below this are reserved , for example
* 0 is " no interrupt " , and 2 is used for IPIs .
*/
# define KVMPPC_XICS_FIRST_IRQ 16
# define KVMPPC_XICS_NR_IRQS ((KVMPPC_XICS_MAX_ICS_ID + 1) * \
KVMPPC_XICS_IRQ_PER_ICS )
/* Priority value to use for disabling an interrupt */
# define MASKED 0xff
/* State for one irq source */
struct ics_irq_state {
u32 number ;
u32 server ;
u8 priority ;
u8 saved_priority ; /* currently unused */
u8 resend ;
u8 masked_pending ;
u8 asserted ; /* Only for LSI */
u8 exists ;
} ;
/* Atomic ICP state, updated with a single compare & swap */
union kvmppc_icp_state {
unsigned long raw ;
struct {
u8 out_ee : 1 ;
u8 need_resend : 1 ;
u8 cppr ;
u8 mfrr ;
u8 pending_pri ;
u32 xisr ;
} ;
} ;
/* One bit per ICS */
# define ICP_RESEND_MAP_SIZE (KVMPPC_XICS_MAX_ICS_ID / BITS_PER_LONG + 1)
struct kvmppc_icp {
struct kvm_vcpu * vcpu ;
unsigned long server_num ;
union kvmppc_icp_state state ;
unsigned long resend_map [ ICP_RESEND_MAP_SIZE ] ;
2013-04-17 20:31:15 +00:00
/* Real mode might find something too hard, here's the action
* it might request from virtual mode
*/
# define XICS_RM_KICK_VCPU 0x1
# define XICS_RM_CHECK_RESEND 0x2
# define XICS_RM_REJECT 0x4
u32 rm_action ;
struct kvm_vcpu * rm_kick_target ;
u32 rm_reject ;
/* Debug stuff for real mode */
union kvmppc_icp_state rm_dbgstate ;
struct kvm_vcpu * rm_dbgtgt ;
2013-04-17 20:30:26 +00:00
} ;
struct kvmppc_ics {
struct mutex lock ;
u16 icsid ;
struct ics_irq_state irq_state [ KVMPPC_XICS_IRQ_PER_ICS ] ;
} ;
struct kvmppc_xics {
struct kvm * kvm ;
struct dentry * dentry ;
u32 max_icsid ;
2013-04-17 20:31:15 +00:00
bool real_mode ;
bool real_mode_dbg ;
2013-04-17 20:30:26 +00:00
struct kvmppc_ics * ics [ KVMPPC_XICS_MAX_ICS_ID + 1 ] ;
} ;
static inline struct kvmppc_icp * kvmppc_xics_find_server ( struct kvm * kvm ,
u32 nr )
{
struct kvm_vcpu * vcpu = NULL ;
int i ;
kvm_for_each_vcpu ( i , vcpu , kvm ) {
if ( vcpu - > arch . icp & & nr = = vcpu - > arch . icp - > server_num )
return vcpu - > arch . icp ;
}
return NULL ;
}
static inline struct kvmppc_ics * kvmppc_xics_find_ics ( struct kvmppc_xics * xics ,
u32 irq , u16 * source )
{
u32 icsid = irq > > KVMPPC_XICS_ICS_SHIFT ;
u16 src = irq & KVMPPC_XICS_SRC_MASK ;
struct kvmppc_ics * ics ;
if ( source )
* source = src ;
if ( icsid > KVMPPC_XICS_MAX_ICS_ID )
return NULL ;
ics = xics - > ics [ icsid ] ;
if ( ! ics )
return NULL ;
return ics ;
}
# endif /* _KVM_PPC_BOOK3S_XICS_H */