2008-10-06 09:48:45 +04:00
/*
* irq_comm . c : Common API for in kernel interrupt controller
* Copyright ( c ) 2007 , Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . , 59 Temple
* Place - Suite 330 , Boston , MA 02111 - 1307 USA .
* Authors :
* Yaozu ( Eddie ) Dong < Eddie . dong @ intel . com >
*
*/
# include <linux/kvm_host.h>
2009-02-10 08:57:06 +03:00
# include <asm/msidef.h>
2008-10-06 09:48:45 +04:00
# include "irq.h"
# include "ioapic.h"
2009-02-04 18:28:14 +03:00
static int kvm_set_pic_irq ( struct kvm_kernel_irq_routing_entry * e ,
struct kvm * kvm , int level )
2008-11-19 14:58:46 +03:00
{
# ifdef CONFIG_X86
2009-02-04 18:28:14 +03:00
return kvm_pic_set_irq ( pic_irqchip ( kvm ) , e - > irqchip . pin , level ) ;
# else
return - 1 ;
2008-11-19 14:58:46 +03:00
# endif
}
2009-02-04 18:28:14 +03:00
static int kvm_set_ioapic_irq ( struct kvm_kernel_irq_routing_entry * e ,
struct kvm * kvm , int level )
2008-11-19 14:58:46 +03:00
{
2009-02-04 18:28:14 +03:00
return kvm_ioapic_set_irq ( kvm - > arch . vioapic , e - > irqchip . pin , level ) ;
2008-11-19 14:58:46 +03:00
}
2009-02-04 18:28:14 +03:00
static int kvm_set_msi ( struct kvm_kernel_irq_routing_entry * e ,
struct kvm * kvm , int level )
2009-02-10 08:57:06 +03:00
{
2009-02-23 13:57:11 +03:00
int vcpu_id , r = - 1 ;
2009-02-10 08:57:06 +03:00
struct kvm_vcpu * vcpu ;
struct kvm_ioapic * ioapic = ioapic_irqchip ( kvm ) ;
int dest_id = ( e - > msi . address_lo & MSI_ADDR_DEST_ID_MASK )
> > MSI_ADDR_DEST_ID_SHIFT ;
int vector = ( e - > msi . data & MSI_DATA_VECTOR_MASK )
> > MSI_DATA_VECTOR_SHIFT ;
int dest_mode = test_bit ( MSI_ADDR_DEST_MODE_SHIFT ,
( unsigned long * ) & e - > msi . address_lo ) ;
int trig_mode = test_bit ( MSI_DATA_TRIGGER_SHIFT ,
( unsigned long * ) & e - > msi . data ) ;
int delivery_mode = test_bit ( MSI_DATA_DELIVERY_MODE_SHIFT ,
( unsigned long * ) & e - > msi . data ) ;
u32 deliver_bitmask ;
BUG_ON ( ! ioapic ) ;
deliver_bitmask = kvm_ioapic_get_delivery_bitmask ( ioapic ,
dest_id , dest_mode ) ;
/* IOAPIC delivery mode value is the same as MSI here */
switch ( delivery_mode ) {
case IOAPIC_LOWEST_PRIORITY :
vcpu = kvm_get_lowest_prio_vcpu ( ioapic - > kvm , vector ,
deliver_bitmask ) ;
if ( vcpu ! = NULL )
2009-02-23 13:57:11 +03:00
r = kvm_apic_set_irq ( vcpu , vector , trig_mode ) ;
2009-02-10 08:57:06 +03:00
else
printk ( KERN_INFO " kvm: null lowest priority vcpu! \n " ) ;
break ;
case IOAPIC_FIXED :
for ( vcpu_id = 0 ; deliver_bitmask ! = 0 ; vcpu_id + + ) {
if ( ! ( deliver_bitmask & ( 1 < < vcpu_id ) ) )
continue ;
deliver_bitmask & = ~ ( 1 < < vcpu_id ) ;
vcpu = ioapic - > kvm - > vcpus [ vcpu_id ] ;
2009-02-23 13:57:11 +03:00
if ( vcpu ) {
if ( r < 0 )
r = 0 ;
r + = kvm_apic_set_irq ( vcpu , vector , trig_mode ) ;
}
2009-02-10 08:57:06 +03:00
}
break ;
default :
break ;
}
2009-02-23 13:57:11 +03:00
return r ;
2009-02-10 08:57:06 +03:00
}
2009-02-04 18:28:14 +03:00
/* This should be called with the kvm->lock mutex held
* Return value :
* < 0 Interrupt was ignored ( masked or not delivered for other reasons )
* = 0 Interrupt was coalesced ( previous irq is still pending )
* > 0 Number of CPUs interrupt was delivered to
*/
int kvm_set_irq ( struct kvm * kvm , int irq_source_id , int irq , int level )
2008-10-06 09:48:45 +04:00
{
2008-11-19 14:58:46 +03:00
struct kvm_kernel_irq_routing_entry * e ;
2009-02-10 08:57:06 +03:00
unsigned long * irq_state , sig_level ;
2009-02-04 18:28:14 +03:00
int ret = - 1 ;
2009-02-10 08:57:06 +03:00
if ( irq < KVM_IOAPIC_NUM_PINS ) {
irq_state = ( unsigned long * ) & kvm - > arch . irq_states [ irq ] ;
2008-10-15 16:15:06 +04:00
2009-02-10 08:57:06 +03:00
/* Logical OR for level trig interrupt */
if ( level )
set_bit ( irq_source_id , irq_state ) ;
else
clear_bit ( irq_source_id , irq_state ) ;
sig_level = ! ! ( * irq_state ) ;
} else /* Deal with MSI/MSI-X */
sig_level = 1 ;
2008-10-15 16:15:06 +04:00
2008-10-06 09:48:45 +04:00
/* Not possible to detect if the guest uses the PIC or the
* IOAPIC . So set the bit in both . The guest will ignore
* writes to the unused one .
*/
2008-11-19 14:58:46 +03:00
list_for_each_entry ( e , & kvm - > irq_routing , link )
2009-02-04 18:28:14 +03:00
if ( e - > gsi = = irq ) {
int r = e - > set ( e , kvm , sig_level ) ;
if ( r < 0 )
continue ;
ret = r + ( ( ret < 0 ) ? 0 : ret ) ;
}
return ret ;
2008-10-06 09:48:45 +04:00
}
2009-01-27 20:12:38 +03:00
void kvm_notify_acked_irq ( struct kvm * kvm , unsigned irqchip , unsigned pin )
2008-10-06 09:48:45 +04:00
{
2009-01-27 20:12:38 +03:00
struct kvm_kernel_irq_routing_entry * e ;
2008-10-06 09:48:45 +04:00
struct kvm_irq_ack_notifier * kian ;
struct hlist_node * n ;
2009-01-27 20:12:38 +03:00
unsigned gsi = pin ;
list_for_each_entry ( e , & kvm - > irq_routing , link )
if ( e - > irqchip . irqchip = = irqchip & &
e - > irqchip . pin = = pin ) {
gsi = e - > gsi ;
break ;
}
2008-10-06 09:48:45 +04:00
hlist_for_each_entry ( kian , n , & kvm - > arch . irq_ack_notifier_list , link )
if ( kian - > gsi = = gsi )
kian - > irq_acked ( kian ) ;
}
void kvm_register_irq_ack_notifier ( struct kvm * kvm ,
struct kvm_irq_ack_notifier * kian )
{
hlist_add_head ( & kian - > link , & kvm - > arch . irq_ack_notifier_list ) ;
}
2008-10-20 12:07:10 +04:00
void kvm_unregister_irq_ack_notifier ( struct kvm_irq_ack_notifier * kian )
2008-10-06 09:48:45 +04:00
{
2008-12-01 16:57:46 +03:00
hlist_del_init ( & kian - > link ) ;
2008-10-06 09:48:45 +04:00
}
2008-10-15 16:15:06 +04:00
/* The caller must hold kvm->lock mutex */
int kvm_request_irq_source_id ( struct kvm * kvm )
{
unsigned long * bitmap = & kvm - > arch . irq_sources_bitmap ;
int irq_source_id = find_first_zero_bit ( bitmap ,
sizeof ( kvm - > arch . irq_sources_bitmap ) ) ;
2008-12-01 16:57:48 +03:00
2008-10-15 16:15:06 +04:00
if ( irq_source_id > = sizeof ( kvm - > arch . irq_sources_bitmap ) ) {
printk ( KERN_WARNING " kvm: exhaust allocatable IRQ sources! \n " ) ;
2008-12-01 16:57:48 +03:00
return - EFAULT ;
}
ASSERT ( irq_source_id ! = KVM_USERSPACE_IRQ_SOURCE_ID ) ;
set_bit ( irq_source_id , bitmap ) ;
2008-10-15 16:15:06 +04:00
return irq_source_id ;
}
void kvm_free_irq_source_id ( struct kvm * kvm , int irq_source_id )
{
int i ;
2008-12-01 16:57:48 +03:00
ASSERT ( irq_source_id ! = KVM_USERSPACE_IRQ_SOURCE_ID ) ;
if ( irq_source_id < 0 | |
2008-10-15 16:15:06 +04:00
irq_source_id > = sizeof ( kvm - > arch . irq_sources_bitmap ) ) {
printk ( KERN_ERR " kvm: IRQ source ID out of range! \n " ) ;
return ;
}
for ( i = 0 ; i < KVM_IOAPIC_NUM_PINS ; i + + )
clear_bit ( irq_source_id , & kvm - > arch . irq_states [ i ] ) ;
clear_bit ( irq_source_id , & kvm - > arch . irq_sources_bitmap ) ;
}
2009-01-04 18:10:50 +03:00
void kvm_register_irq_mask_notifier ( struct kvm * kvm , int irq ,
struct kvm_irq_mask_notifier * kimn )
{
kimn - > irq = irq ;
hlist_add_head ( & kimn - > link , & kvm - > mask_notifier_list ) ;
}
void kvm_unregister_irq_mask_notifier ( struct kvm * kvm , int irq ,
struct kvm_irq_mask_notifier * kimn )
{
hlist_del ( & kimn - > link ) ;
}
void kvm_fire_mask_notifiers ( struct kvm * kvm , int irq , bool mask )
{
struct kvm_irq_mask_notifier * kimn ;
struct hlist_node * n ;
hlist_for_each_entry ( kimn , n , & kvm - > mask_notifier_list , link )
if ( kimn - > irq = = irq )
kimn - > func ( kimn , mask ) ;
}
2008-11-19 14:58:46 +03:00
static void __kvm_free_irq_routing ( struct list_head * irq_routing )
{
struct kvm_kernel_irq_routing_entry * e , * n ;
list_for_each_entry_safe ( e , n , irq_routing , link )
kfree ( e ) ;
}
void kvm_free_irq_routing ( struct kvm * kvm )
{
__kvm_free_irq_routing ( & kvm - > irq_routing ) ;
}
2009-02-21 04:19:13 +03:00
static int setup_routing_entry ( struct kvm_kernel_irq_routing_entry * e ,
const struct kvm_irq_routing_entry * ue )
2008-11-19 14:58:46 +03:00
{
int r = - EINVAL ;
int delta ;
e - > gsi = ue - > gsi ;
switch ( ue - > type ) {
case KVM_IRQ_ROUTING_IRQCHIP :
delta = 0 ;
switch ( ue - > u . irqchip . irqchip ) {
case KVM_IRQCHIP_PIC_MASTER :
e - > set = kvm_set_pic_irq ;
break ;
case KVM_IRQCHIP_PIC_SLAVE :
2009-02-04 18:28:14 +03:00
e - > set = kvm_set_pic_irq ;
2008-11-19 14:58:46 +03:00
delta = 8 ;
break ;
case KVM_IRQCHIP_IOAPIC :
e - > set = kvm_set_ioapic_irq ;
break ;
default :
goto out ;
}
e - > irqchip . irqchip = ue - > u . irqchip . irqchip ;
e - > irqchip . pin = ue - > u . irqchip . pin + delta ;
break ;
2009-02-10 08:57:06 +03:00
case KVM_IRQ_ROUTING_MSI :
e - > set = kvm_set_msi ;
e - > msi . address_lo = ue - > u . msi . address_lo ;
e - > msi . address_hi = ue - > u . msi . address_hi ;
e - > msi . data = ue - > u . msi . data ;
break ;
2008-11-19 14:58:46 +03:00
default :
goto out ;
}
r = 0 ;
out :
return r ;
}
int kvm_set_irq_routing ( struct kvm * kvm ,
const struct kvm_irq_routing_entry * ue ,
unsigned nr ,
unsigned flags )
{
struct list_head irq_list = LIST_HEAD_INIT ( irq_list ) ;
struct list_head tmp = LIST_HEAD_INIT ( tmp ) ;
struct kvm_kernel_irq_routing_entry * e = NULL ;
unsigned i ;
int r ;
for ( i = 0 ; i < nr ; + + i ) {
r = - EINVAL ;
if ( ue - > gsi > = KVM_MAX_IRQ_ROUTES )
goto out ;
if ( ue - > flags )
goto out ;
r = - ENOMEM ;
e = kzalloc ( sizeof ( * e ) , GFP_KERNEL ) ;
if ( ! e )
goto out ;
r = setup_routing_entry ( e , ue ) ;
if ( r )
goto out ;
+ + ue ;
list_add ( & e - > link , & irq_list ) ;
e = NULL ;
}
mutex_lock ( & kvm - > lock ) ;
list_splice ( & kvm - > irq_routing , & tmp ) ;
INIT_LIST_HEAD ( & kvm - > irq_routing ) ;
list_splice ( & irq_list , & kvm - > irq_routing ) ;
INIT_LIST_HEAD ( & irq_list ) ;
list_splice ( & tmp , & irq_list ) ;
mutex_unlock ( & kvm - > lock ) ;
r = 0 ;
out :
kfree ( e ) ;
__kvm_free_irq_routing ( & irq_list ) ;
return r ;
}
# define IOAPIC_ROUTING_ENTRY(irq) \
{ . gsi = irq , . type = KVM_IRQ_ROUTING_IRQCHIP , \
. u . irqchip . irqchip = KVM_IRQCHIP_IOAPIC , . u . irqchip . pin = ( irq ) }
# define ROUTING_ENTRY1(irq) IOAPIC_ROUTING_ENTRY(irq)
# ifdef CONFIG_X86
# define PIC_ROUTING_ENTRY(irq) \
{ . gsi = irq , . type = KVM_IRQ_ROUTING_IRQCHIP , \
. u . irqchip . irqchip = SELECT_PIC ( irq ) , . u . irqchip . pin = ( irq ) % 8 }
# define ROUTING_ENTRY2(irq) \
IOAPIC_ROUTING_ENTRY ( irq ) , PIC_ROUTING_ENTRY ( irq )
# else
# define ROUTING_ENTRY2(irq) \
IOAPIC_ROUTING_ENTRY ( irq )
# endif
static const struct kvm_irq_routing_entry default_routing [ ] = {
ROUTING_ENTRY2 ( 0 ) , ROUTING_ENTRY2 ( 1 ) ,
ROUTING_ENTRY2 ( 2 ) , ROUTING_ENTRY2 ( 3 ) ,
ROUTING_ENTRY2 ( 4 ) , ROUTING_ENTRY2 ( 5 ) ,
ROUTING_ENTRY2 ( 6 ) , ROUTING_ENTRY2 ( 7 ) ,
ROUTING_ENTRY2 ( 8 ) , ROUTING_ENTRY2 ( 9 ) ,
ROUTING_ENTRY2 ( 10 ) , ROUTING_ENTRY2 ( 11 ) ,
ROUTING_ENTRY2 ( 12 ) , ROUTING_ENTRY2 ( 13 ) ,
ROUTING_ENTRY2 ( 14 ) , ROUTING_ENTRY2 ( 15 ) ,
ROUTING_ENTRY1 ( 16 ) , ROUTING_ENTRY1 ( 17 ) ,
ROUTING_ENTRY1 ( 18 ) , ROUTING_ENTRY1 ( 19 ) ,
ROUTING_ENTRY1 ( 20 ) , ROUTING_ENTRY1 ( 21 ) ,
ROUTING_ENTRY1 ( 22 ) , ROUTING_ENTRY1 ( 23 ) ,
# ifdef CONFIG_IA64
ROUTING_ENTRY1 ( 24 ) , ROUTING_ENTRY1 ( 25 ) ,
ROUTING_ENTRY1 ( 26 ) , ROUTING_ENTRY1 ( 27 ) ,
ROUTING_ENTRY1 ( 28 ) , ROUTING_ENTRY1 ( 29 ) ,
ROUTING_ENTRY1 ( 30 ) , ROUTING_ENTRY1 ( 31 ) ,
ROUTING_ENTRY1 ( 32 ) , ROUTING_ENTRY1 ( 33 ) ,
ROUTING_ENTRY1 ( 34 ) , ROUTING_ENTRY1 ( 35 ) ,
ROUTING_ENTRY1 ( 36 ) , ROUTING_ENTRY1 ( 37 ) ,
ROUTING_ENTRY1 ( 38 ) , ROUTING_ENTRY1 ( 39 ) ,
ROUTING_ENTRY1 ( 40 ) , ROUTING_ENTRY1 ( 41 ) ,
ROUTING_ENTRY1 ( 42 ) , ROUTING_ENTRY1 ( 43 ) ,
ROUTING_ENTRY1 ( 44 ) , ROUTING_ENTRY1 ( 45 ) ,
ROUTING_ENTRY1 ( 46 ) , ROUTING_ENTRY1 ( 47 ) ,
# endif
} ;
int kvm_setup_default_irq_routing ( struct kvm * kvm )
{
return kvm_set_irq_routing ( kvm , default_routing ,
ARRAY_SIZE ( default_routing ) , 0 ) ;
}