2006-04-10 21:17:48 -05:00
/*
* MSI hooks for standard x86 apic
*/
# include <linux/pci.h>
# include <linux/irq.h>
2006-10-04 02:16:59 -07:00
# include <linux/msi.h>
2008-10-17 12:14:13 -07:00
# include <linux/dmar.h>
2006-06-26 14:00:02 +02:00
# include <asm/smp.h>
2009-02-16 15:14:48 +08:00
# include <asm/msidef.h>
2006-04-10 21:17:48 -05:00
2006-10-04 02:16:59 -07:00
static struct irq_chip ia64_msi_chip ;
2006-04-10 21:17:48 -05:00
2006-10-04 02:16:59 -07:00
# ifdef CONFIG_SMP
2011-02-04 20:18:43 +01:00
static int ia64_set_msi_irq_affinity ( struct irq_data * idata ,
const cpumask_t * cpu_mask , bool force )
2006-04-10 21:17:48 -05:00
{
2006-10-04 02:16:59 -07:00
struct msi_msg msg ;
2007-07-17 21:22:48 +09:00
u32 addr , data ;
2008-12-13 21:20:26 +10:30
int cpu = first_cpu ( * cpu_mask ) ;
2011-02-04 20:18:43 +01:00
unsigned int irq = idata - > irq ;
2006-10-04 02:16:59 -07:00
2007-07-17 21:22:48 +09:00
if ( ! cpu_online ( cpu ) )
2009-04-27 17:59:21 -07:00
return - 1 ;
2007-07-17 21:22:48 +09:00
2008-02-25 14:32:22 +09:00
if ( irq_prepare_move ( irq , cpu ) )
2009-04-27 17:59:21 -07:00
return - 1 ;
2007-07-17 21:22:33 +09:00
2010-07-23 14:56:28 +01:00
get_cached_msi_msg ( irq , & msg ) ;
2006-04-10 21:17:48 -05:00
2006-10-04 02:16:59 -07:00
addr = msg . address_lo ;
2009-02-16 15:14:48 +08:00
addr & = MSI_ADDR_DEST_ID_MASK ;
addr | = MSI_ADDR_DEST_ID_CPU ( cpu_physical_id ( cpu ) ) ;
2006-10-04 02:16:59 -07:00
msg . address_lo = addr ;
2006-04-10 21:17:48 -05:00
2007-07-17 21:22:48 +09:00
data = msg . data ;
data & = MSI_DATA_VECTOR_MASK ;
data | = MSI_DATA_VECTOR ( irq_to_vector ( irq ) ) ;
msg . data = data ;
2006-10-04 02:16:59 -07:00
write_msi_msg ( irq , & msg ) ;
2011-02-04 20:18:43 +01:00
cpumask_copy ( idata - > affinity , cpumask_of ( cpu ) ) ;
2009-04-27 17:59:21 -07:00
return 0 ;
2006-04-10 21:17:48 -05:00
}
2006-10-04 02:16:59 -07:00
# endif /* CONFIG_SMP */
2006-04-10 21:17:48 -05:00
2007-01-28 12:56:37 -07:00
int ia64_setup_msi_irq ( struct pci_dev * pdev , struct msi_desc * desc )
2006-04-10 21:17:48 -05:00
{
2006-10-04 02:16:59 -07:00
struct msi_msg msg ;
2006-04-10 21:17:48 -05:00
unsigned long dest_phys_id ;
2007-03-26 09:38:42 +09:00
int irq , vector ;
2007-07-17 21:22:33 +09:00
cpumask_t mask ;
2006-04-10 21:17:48 -05:00
2007-01-28 12:56:37 -07:00
irq = create_irq ( ) ;
if ( irq < 0 )
return irq ;
2011-03-25 21:06:09 +01:00
irq_set_msi_desc ( irq , desc ) ;
2012-03-28 14:42:46 -07:00
cpumask_and ( & mask , & ( irq_to_domain ( irq ) ) , cpu_online_mask ) ;
2007-07-17 21:22:33 +09:00
dest_phys_id = cpu_physical_id ( first_cpu ( mask ) ) ;
2007-04-06 16:51:12 +09:00
vector = irq_to_vector ( irq ) ;
2006-04-10 21:17:48 -05:00
2006-10-04 02:16:59 -07:00
msg . address_hi = 0 ;
msg . address_lo =
2006-10-04 02:16:34 -07:00
MSI_ADDR_HEADER |
2009-02-16 15:14:48 +08:00
MSI_ADDR_DEST_MODE_PHYS |
2006-10-04 02:16:34 -07:00
MSI_ADDR_REDIRECTION_CPU |
2009-02-16 15:14:48 +08:00
MSI_ADDR_DEST_ID_CPU ( dest_phys_id ) ;
2006-04-10 21:17:48 -05:00
2006-10-04 02:16:59 -07:00
msg . data =
2006-10-04 02:16:34 -07:00
MSI_DATA_TRIGGER_EDGE |
2006-04-10 21:17:48 -05:00
MSI_DATA_LEVEL_ASSERT |
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR ( vector ) ;
2006-10-04 02:16:59 -07:00
write_msi_msg ( irq , & msg ) ;
2011-03-25 21:06:09 +01:00
irq_set_chip_and_handler ( irq , & ia64_msi_chip , handle_edge_irq ) ;
2006-10-04 02:16:59 -07:00
2007-10-30 16:01:49 +09:00
return 0 ;
2006-04-10 21:17:48 -05:00
}
2006-10-04 02:16:59 -07:00
void ia64_teardown_msi_irq ( unsigned int irq )
2006-04-10 21:17:48 -05:00
{
2007-01-28 12:56:37 -07:00
destroy_irq ( irq ) ;
2006-04-10 21:17:48 -05:00
}
2011-02-04 20:18:43 +01:00
static void ia64_ack_msi_irq ( struct irq_data * data )
2006-10-04 02:16:59 -07:00
{
2011-02-04 20:18:43 +01:00
irq_complete_move ( data - > irq ) ;
2011-03-25 20:36:55 +01:00
irq_move_irq ( data ) ;
2006-10-04 02:16:59 -07:00
ia64_eoi ( ) ;
}
2011-02-04 20:18:43 +01:00
static int ia64_msi_retrigger_irq ( struct irq_data * data )
2006-10-04 02:16:59 -07:00
{
2011-02-04 20:18:43 +01:00
unsigned int vector = irq_to_vector ( data - > irq ) ;
2006-10-04 02:16:59 -07:00
ia64_resend_irq ( vector ) ;
return 1 ;
}
2006-04-10 21:17:48 -05:00
/*
2006-10-04 02:16:59 -07:00
* Generic ops used on most IA64 platforms .
2006-04-10 21:17:48 -05:00
*/
2006-10-04 02:16:59 -07:00
static struct irq_chip ia64_msi_chip = {
2011-02-04 20:18:43 +01:00
. name = " PCI-MSI " ,
. irq_mask = mask_msi_irq ,
. irq_unmask = unmask_msi_irq ,
. irq_ack = ia64_ack_msi_irq ,
2006-10-04 02:16:59 -07:00
# ifdef CONFIG_SMP
2011-02-04 20:18:43 +01:00
. irq_set_affinity = ia64_set_msi_irq_affinity ,
2006-10-04 02:16:59 -07:00
# endif
2011-02-04 20:18:43 +01:00
. irq_retrigger = ia64_msi_retrigger_irq ,
2006-04-10 21:17:48 -05:00
} ;
2006-10-04 02:16:59 -07:00
2007-01-28 12:56:37 -07:00
int arch_setup_msi_irq ( struct pci_dev * pdev , struct msi_desc * desc )
2006-10-04 02:16:59 -07:00
{
if ( platform_setup_msi_irq )
2007-01-28 12:56:37 -07:00
return platform_setup_msi_irq ( pdev , desc ) ;
2006-10-04 02:16:59 -07:00
2007-01-28 12:56:37 -07:00
return ia64_setup_msi_irq ( pdev , desc ) ;
2006-10-04 02:16:59 -07: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 12:14:13 -07:00
2011-08-23 17:05:25 -07:00
# ifdef CONFIG_INTEL_IOMMU
2008-10-17 12:14:13 -07:00
# ifdef CONFIG_SMP
2011-02-04 20:18:43 +01:00
static int dmar_msi_set_affinity ( struct irq_data * data ,
const struct cpumask * mask , bool force )
2008-10-17 12:14:13 -07:00
{
2011-02-04 20:18:43 +01:00
unsigned int irq = data - > irq ;
2008-10-17 12:14:13 -07:00
struct irq_cfg * cfg = irq_cfg + irq ;
struct msi_msg msg ;
2008-12-13 21:20:26 +10:30
int cpu = cpumask_first ( mask ) ;
2008-10-17 12:14:13 -07:00
if ( ! cpu_online ( cpu ) )
2009-04-27 17:59:21 -07:00
return - 1 ;
2008-10-17 12:14:13 -07:00
if ( irq_prepare_move ( irq , cpu ) )
2009-04-27 17:59:21 -07:00
return - 1 ;
2008-10-17 12:14:13 -07:00
dmar_msi_read ( irq , & msg ) ;
msg . data & = ~ MSI_DATA_VECTOR_MASK ;
msg . data | = MSI_DATA_VECTOR ( cfg - > vector ) ;
2009-02-16 15:14:48 +08:00
msg . address_lo & = ~ MSI_ADDR_DEST_ID_MASK ;
msg . address_lo | = MSI_ADDR_DEST_ID_CPU ( cpu_physical_id ( cpu ) ) ;
2008-10-17 12:14:13 -07:00
dmar_msi_write ( irq , & msg ) ;
2011-02-04 20:18:43 +01:00
cpumask_copy ( data - > affinity , mask ) ;
2009-04-27 17:59:21 -07:00
return 0 ;
2008-10-17 12:14:13 -07:00
}
# endif /* CONFIG_SMP */
2009-06-10 12:45:01 -07:00
static struct irq_chip dmar_msi_type = {
2008-10-17 12:14:13 -07:00
. name = " DMAR_MSI " ,
2010-09-28 17:15:11 +02:00
. irq_unmask = dmar_msi_unmask ,
. irq_mask = dmar_msi_mask ,
2011-02-04 20:18:43 +01:00
. irq_ack = ia64_ack_msi_irq ,
2008-10-17 12:14:13 -07:00
# ifdef CONFIG_SMP
2011-02-04 20:18:43 +01:00
. irq_set_affinity = dmar_msi_set_affinity ,
2008-10-17 12:14:13 -07:00
# endif
2011-02-04 20:18:43 +01:00
. irq_retrigger = ia64_msi_retrigger_irq ,
2008-10-17 12:14:13 -07:00
} ;
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 ;
2012-03-28 14:42:46 -07:00
cpumask_and ( & mask , & ( irq_to_domain ( irq ) ) , cpu_online_mask ) ;
2008-10-17 12:14:13 -07:00
dest = cpu_physical_id ( first_cpu ( mask ) ) ;
msg - > address_hi = 0 ;
msg - > address_lo =
MSI_ADDR_HEADER |
2009-02-16 15:14:48 +08:00
MSI_ADDR_DEST_MODE_PHYS |
2008-10-17 12:14:13 -07:00
MSI_ADDR_REDIRECTION_CPU |
2009-02-16 15:14:48 +08:00
MSI_ADDR_DEST_ID_CPU ( dest ) ;
2008-10-17 12:14:13 -07: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 ) ;
2011-03-25 21:06:09 +01:00
irq_set_chip_and_handler_name ( irq , & dmar_msi_type , handle_edge_irq ,
" edge " ) ;
2008-10-17 12:14:13 -07:00
return 0 ;
}
2011-08-23 17:05:25 -07:00
# endif /* CONFIG_INTEL_IOMMU */
2008-10-17 12:14:13 -07:00