2006-04-11 06:17:48 +04:00
/*
* MSI hooks for standard x86 apic
*/
# include <linux/pci.h>
# include <linux/irq.h>
2006-10-04 13:16:59 +04:00
# include <linux/msi.h>
2008-10-17 23:14:13 +04:00
# include <linux/dmar.h>
2006-06-26 16:00:02 +04:00
# include <asm/smp.h>
2009-02-16 10:14:48 +03:00
# include <asm/msidef.h>
2006-04-11 06:17:48 +04:00
2006-10-04 13:16:59 +04:00
static struct irq_chip ia64_msi_chip ;
2006-04-11 06:17:48 +04:00
2006-10-04 13:16:59 +04:00
# ifdef CONFIG_SMP
2009-04-28 04:59:21 +04:00
static int ia64_set_msi_irq_affinity ( unsigned int irq ,
2008-12-13 13:50:26 +03:00
const cpumask_t * cpu_mask )
2006-04-11 06:17:48 +04:00
{
2006-10-04 13:16:59 +04:00
struct msi_msg msg ;
2007-07-17 16:22:48 +04:00
u32 addr , data ;
2008-12-13 13:50:26 +03:00
int cpu = first_cpu ( * cpu_mask ) ;
2006-10-04 13:16:59 +04:00
2007-07-17 16:22:48 +04:00
if ( ! cpu_online ( cpu ) )
2009-04-28 04:59:21 +04:00
return - 1 ;
2007-07-17 16:22:48 +04:00
2008-02-25 08:32:22 +03:00
if ( irq_prepare_move ( irq , cpu ) )
2009-04-28 04:59:21 +04:00
return - 1 ;
2007-07-17 16:22:33 +04:00
2010-07-23 17:56:28 +04:00
get_cached_msi_msg ( irq , & msg ) ;
2006-04-11 06:17:48 +04:00
2006-10-04 13:16:59 +04:00
addr = msg . address_lo ;
2009-02-16 10:14:48 +03:00
addr & = MSI_ADDR_DEST_ID_MASK ;
addr | = MSI_ADDR_DEST_ID_CPU ( cpu_physical_id ( cpu ) ) ;
2006-10-04 13:16:59 +04:00
msg . address_lo = addr ;
2006-04-11 06:17:48 +04:00
2007-07-17 16:22:48 +04:00
data = msg . data ;
data & = MSI_DATA_VECTOR_MASK ;
data | = MSI_DATA_VECTOR ( irq_to_vector ( irq ) ) ;
msg . data = data ;
2006-10-04 13:16:59 +04:00
write_msi_msg ( irq , & msg ) ;
2009-01-13 02:27:13 +03:00
cpumask_copy ( irq_desc [ irq ] . affinity , cpumask_of ( cpu ) ) ;
2009-04-28 04:59:21 +04:00
return 0 ;
2006-04-11 06:17:48 +04:00
}
2006-10-04 13:16:59 +04:00
# endif /* CONFIG_SMP */
2006-04-11 06:17:48 +04:00
2007-01-28 22:56:37 +03:00
int ia64_setup_msi_irq ( struct pci_dev * pdev , struct msi_desc * desc )
2006-04-11 06:17:48 +04:00
{
2006-10-04 13:16:59 +04:00
struct msi_msg msg ;
2006-04-11 06:17:48 +04:00
unsigned long dest_phys_id ;
2007-03-26 04:38:42 +04:00
int irq , vector ;
2007-07-17 16:22:33 +04:00
cpumask_t mask ;
2006-04-11 06:17:48 +04:00
2007-01-28 22:56:37 +03:00
irq = create_irq ( ) ;
if ( irq < 0 )
return irq ;
set_irq_msi ( irq , desc ) ;
2007-07-17 16:22:33 +04:00
cpus_and ( mask , irq_to_domain ( irq ) , cpu_online_map ) ;
dest_phys_id = cpu_physical_id ( first_cpu ( mask ) ) ;
2007-04-06 11:51:12 +04:00
vector = irq_to_vector ( irq ) ;
2006-04-11 06:17:48 +04:00
2006-10-04 13:16:59 +04:00
msg . address_hi = 0 ;
msg . address_lo =
2006-10-04 13:16:34 +04:00
MSI_ADDR_HEADER |
2009-02-16 10:14:48 +03:00
MSI_ADDR_DEST_MODE_PHYS |
2006-10-04 13:16:34 +04:00
MSI_ADDR_REDIRECTION_CPU |
2009-02-16 10:14:48 +03:00
MSI_ADDR_DEST_ID_CPU ( dest_phys_id ) ;
2006-04-11 06:17:48 +04:00
2006-10-04 13:16:59 +04:00
msg . data =
2006-10-04 13:16:34 +04:00
MSI_DATA_TRIGGER_EDGE |
2006-04-11 06:17:48 +04:00
MSI_DATA_LEVEL_ASSERT |
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR ( vector ) ;
2006-10-04 13:16:59 +04:00
write_msi_msg ( irq , & msg ) ;
set_irq_chip_and_handler ( irq , & ia64_msi_chip , handle_edge_irq ) ;
2007-10-30 10:01:49 +03:00
return 0 ;
2006-04-11 06:17:48 +04:00
}
2006-10-04 13:16:59 +04:00
void ia64_teardown_msi_irq ( unsigned int irq )
2006-04-11 06:17:48 +04:00
{
2007-01-28 22:56:37 +03:00
destroy_irq ( irq ) ;
2006-04-11 06:17:48 +04:00
}
2006-10-04 13:16:59 +04:00
static void ia64_ack_msi_irq ( unsigned int irq )
{
2008-02-25 08:32:22 +03:00
irq_complete_move ( irq ) ;
2006-10-04 13:16:59 +04:00
move_native_irq ( irq ) ;
ia64_eoi ( ) ;
}
static int ia64_msi_retrigger_irq ( unsigned int irq )
{
2007-04-06 11:51:12 +04:00
unsigned int vector = irq_to_vector ( irq ) ;
2006-10-04 13:16:59 +04:00
ia64_resend_irq ( vector ) ;
return 1 ;
}
2006-04-11 06:17:48 +04:00
/*
2006-10-04 13:16:59 +04:00
* Generic ops used on most IA64 platforms .
2006-04-11 06:17:48 +04:00
*/
2006-10-04 13:16:59 +04:00
static struct irq_chip ia64_msi_chip = {
. name = " PCI-MSI " ,
2010-09-28 18:46:51 +04:00
. irq_mask = mask_msi_irq ,
. irq_unmask = unmask_msi_irq ,
2006-10-04 13:16:59 +04:00
. ack = ia64_ack_msi_irq ,
# ifdef CONFIG_SMP
. set_affinity = ia64_set_msi_irq_affinity ,
# endif
. retrigger = ia64_msi_retrigger_irq ,
2006-04-11 06:17:48 +04:00
} ;
2006-10-04 13:16:59 +04:00
2007-01-28 22:56:37 +03:00
int arch_setup_msi_irq ( struct pci_dev * pdev , struct msi_desc * desc )
2006-10-04 13:16:59 +04:00
{
if ( platform_setup_msi_irq )
2007-01-28 22:56:37 +03:00
return platform_setup_msi_irq ( pdev , desc ) ;
2006-10-04 13:16:59 +04:00
2007-01-28 22:56:37 +03:00
return ia64_setup_msi_irq ( pdev , desc ) ;
2006-10-04 13:16:59 +04:00
}
void arch_teardown_msi_irq ( unsigned int irq )
{
if ( platform_teardown_msi_irq )
return platform_teardown_msi_irq ( irq ) ;
return ia64_teardown_msi_irq ( irq ) ;
}
2008-10-17 23:14:13 +04:00
# ifdef CONFIG_DMAR
# ifdef CONFIG_SMP
2009-04-28 04:59:21 +04:00
static int dmar_msi_set_affinity ( unsigned int irq , const struct cpumask * mask )
2008-10-17 23:14:13 +04:00
{
struct irq_cfg * cfg = irq_cfg + irq ;
struct msi_msg msg ;
2008-12-13 13:50:26 +03:00
int cpu = cpumask_first ( mask ) ;
2008-10-17 23:14:13 +04:00
if ( ! cpu_online ( cpu ) )
2009-04-28 04:59:21 +04:00
return - 1 ;
2008-10-17 23:14:13 +04:00
if ( irq_prepare_move ( irq , cpu ) )
2009-04-28 04:59:21 +04:00
return - 1 ;
2008-10-17 23:14:13 +04:00
dmar_msi_read ( irq , & msg ) ;
msg . data & = ~ MSI_DATA_VECTOR_MASK ;
msg . data | = MSI_DATA_VECTOR ( cfg - > vector ) ;
2009-02-16 10:14:48 +03:00
msg . address_lo & = ~ MSI_ADDR_DEST_ID_MASK ;
msg . address_lo | = MSI_ADDR_DEST_ID_CPU ( cpu_physical_id ( cpu ) ) ;
2008-10-17 23:14:13 +04:00
dmar_msi_write ( irq , & msg ) ;
2009-01-13 02:27:13 +03:00
cpumask_copy ( irq_desc [ irq ] . affinity , mask ) ;
2009-04-28 04:59:21 +04:00
return 0 ;
2008-10-17 23:14:13 +04:00
}
# endif /* CONFIG_SMP */
2009-06-10 23:45:01 +04:00
static struct irq_chip dmar_msi_type = {
2008-10-17 23:14:13 +04:00
. name = " DMAR_MSI " ,
. unmask = dmar_msi_unmask ,
. mask = dmar_msi_mask ,
. ack = ia64_ack_msi_irq ,
# ifdef CONFIG_SMP
. set_affinity = dmar_msi_set_affinity ,
# endif
. retrigger = ia64_msi_retrigger_irq ,
} ;
static int
msi_compose_msg ( struct pci_dev * pdev , unsigned int irq , struct msi_msg * msg )
{
struct irq_cfg * cfg = irq_cfg + irq ;
unsigned dest ;
cpumask_t mask ;
cpus_and ( mask , irq_to_domain ( irq ) , cpu_online_map ) ;
dest = cpu_physical_id ( first_cpu ( mask ) ) ;
msg - > address_hi = 0 ;
msg - > address_lo =
MSI_ADDR_HEADER |
2009-02-16 10:14:48 +03:00
MSI_ADDR_DEST_MODE_PHYS |
2008-10-17 23:14:13 +04:00
MSI_ADDR_REDIRECTION_CPU |
2009-02-16 10:14:48 +03:00
MSI_ADDR_DEST_ID_CPU ( dest ) ;
2008-10-17 23:14:13 +04:00
msg - > data =
MSI_DATA_TRIGGER_EDGE |
MSI_DATA_LEVEL_ASSERT |
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR ( cfg - > vector ) ;
return 0 ;
}
int arch_setup_dmar_msi ( unsigned int irq )
{
int ret ;
struct msi_msg msg ;
ret = msi_compose_msg ( NULL , irq , & msg ) ;
if ( ret < 0 )
return ret ;
dmar_msi_write ( irq , & msg ) ;
set_irq_chip_and_handler_name ( irq , & dmar_msi_type , handle_edge_irq ,
" edge " ) ;
return 0 ;
}
# endif /* CONFIG_DMAR */