@ -73,6 +73,7 @@
static void vgic_retire_disabled_irqs ( struct kvm_vcpu * vcpu ) ;
static void vgic_update_state ( struct kvm * kvm ) ;
static void vgic_kick_vcpus ( struct kvm * kvm ) ;
static void vgic_dispatch_sgi ( struct kvm_vcpu * vcpu , u32 reg ) ;
static u32 * vgic_bitmap_get_reg ( struct vgic_bitmap * x ,
@ -708,6 +709,9 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
kvm_prepare_mmio ( run , mmio ) ;
kvm_handle_mmio_return ( vcpu , run ) ;
if ( updated_state )
vgic_kick_vcpus ( vcpu - > kvm ) ;
return true ;
}
@ -1104,6 +1108,119 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
return test_bit ( vcpu - > vcpu_id , & dist - > irq_pending_on_cpu ) ;
}
static void vgic_kick_vcpus ( struct kvm * kvm )
{
struct kvm_vcpu * vcpu ;
int c ;
/*
* We ' ve injected an interrupt , time to find out who deserves
* a good kick . . .
*/
kvm_for_each_vcpu ( c , vcpu , kvm ) {
if ( kvm_vgic_vcpu_pending_irq ( vcpu ) )
kvm_vcpu_kick ( vcpu ) ;
}
}
static int vgic_validate_injection ( struct kvm_vcpu * vcpu , int irq , int level )
{
int is_edge = vgic_irq_is_edge ( vcpu , irq ) ;
int state = vgic_dist_irq_is_pending ( vcpu , irq ) ;
/*
* Only inject an interrupt if :
* - edge triggered and we have a rising edge
* - level triggered and we change level
*/
if ( is_edge )
return level > state ;
else
return level ! = state ;
}
static bool vgic_update_irq_state ( struct kvm * kvm , int cpuid ,
unsigned int irq_num , bool level )
{
struct vgic_dist * dist = & kvm - > arch . vgic ;
struct kvm_vcpu * vcpu ;
int is_edge , is_level ;
int enabled ;
bool ret = true ;
spin_lock ( & dist - > lock ) ;
vcpu = kvm_get_vcpu ( kvm , cpuid ) ;
is_edge = vgic_irq_is_edge ( vcpu , irq_num ) ;
is_level = ! is_edge ;
if ( ! vgic_validate_injection ( vcpu , irq_num , level ) ) {
ret = false ;
goto out ;
}
if ( irq_num > = VGIC_NR_PRIVATE_IRQS ) {
cpuid = dist - > irq_spi_cpu [ irq_num - VGIC_NR_PRIVATE_IRQS ] ;
vcpu = kvm_get_vcpu ( kvm , cpuid ) ;
}
kvm_debug ( " Inject IRQ%d level %d CPU%d \n " , irq_num , level , cpuid ) ;
if ( level )
vgic_dist_irq_set ( vcpu , irq_num ) ;
else
vgic_dist_irq_clear ( vcpu , irq_num ) ;
enabled = vgic_irq_is_enabled ( vcpu , irq_num ) ;
if ( ! enabled ) {
ret = false ;
goto out ;
}
if ( is_level & & vgic_irq_is_active ( vcpu , irq_num ) ) {
/*
* Level interrupt in progress , will be picked up
* when EOId .
*/
ret = false ;
goto out ;
}
if ( level ) {
vgic_cpu_irq_set ( vcpu , irq_num ) ;
set_bit ( cpuid , & dist - > irq_pending_on_cpu ) ;
}
out :
spin_unlock ( & dist - > lock ) ;
return ret ;
}
/**
* kvm_vgic_inject_irq - Inject an IRQ from a device to the vgic
* @ kvm : The VM structure pointer
* @ cpuid : The CPU for PPIs
* @ irq_num : The IRQ number that is assigned to the device
* @ level : Edge - triggered : true : to trigger the interrupt
* false : to ignore the call
* Level - sensitive true : activates an interrupt
* false : deactivates an interrupt
*
* The GIC is not concerned with devices being active - LOW or active - HIGH for
* level - sensitive interrupts . You can think of the level parameter as 1
* being HIGH and 0 being LOW and all devices being active - HIGH .
*/
int kvm_vgic_inject_irq ( struct kvm * kvm , int cpuid , unsigned int irq_num ,
bool level )
{
if ( vgic_update_irq_state ( kvm , cpuid , irq_num , level ) )
vgic_kick_vcpus ( kvm ) ;
return 0 ;
}
static bool vgic_ioaddr_overlap ( struct kvm * kvm )
{
phys_addr_t dist = kvm - > arch . vgic . vgic_dist_base ;