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
2011-02-04 22:18:43 +03:00
static int ia64_set_msi_irq_affinity ( struct irq_data * idata ,
const cpumask_t * cpu_mask , bool force )
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 ;
2014-03-05 00:43:38 +04:00
int cpu = cpumask_first_and ( cpu_mask , cpu_online_mask ) ;
2011-02-04 22:18:43 +03:00
unsigned int irq = idata - > irq ;
2006-10-04 13:16:59 +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 ) ;
2011-02-04 22:18:43 +03:00
cpumask_copy ( idata - > 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 ;
2011-03-25 23:06:09 +03:00
irq_set_msi_desc ( irq , desc ) ;
2012-03-29 01:42:46 +04:00
cpumask_and ( & mask , & ( irq_to_domain ( irq ) ) , cpu_online_mask ) ;
2007-07-17 16:22:33 +04:00
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 ) ;
2011-03-25 23:06:09 +03:00
irq_set_chip_and_handler ( irq , & ia64_msi_chip , handle_edge_irq ) ;
2006-10-04 13:16:59 +04:00
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
}
2011-02-04 22:18:43 +03:00
static void ia64_ack_msi_irq ( struct irq_data * data )
2006-10-04 13:16:59 +04:00
{
2011-02-04 22:18:43 +03:00
irq_complete_move ( data - > irq ) ;
2011-03-25 22:36:55 +03:00
irq_move_irq ( data ) ;
2006-10-04 13:16:59 +04:00
ia64_eoi ( ) ;
}
2011-02-04 22:18:43 +03:00
static int ia64_msi_retrigger_irq ( struct irq_data * data )
2006-10-04 13:16:59 +04:00
{
2011-02-04 22:18:43 +03:00
unsigned int vector = irq_to_vector ( data - > 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 = {
2011-02-04 22:18:43 +03:00
. name = " PCI-MSI " ,
. irq_mask = mask_msi_irq ,
. irq_unmask = unmask_msi_irq ,
. irq_ack = ia64_ack_msi_irq ,
2006-10-04 13:16:59 +04:00
# ifdef CONFIG_SMP
2011-02-04 22:18:43 +03:00
. irq_set_affinity = ia64_set_msi_irq_affinity ,
2006-10-04 13:16:59 +04:00
# endif
2011-02-04 22:18:43 +03:00
. irq_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
2011-08-24 04:05:25 +04:00
# ifdef CONFIG_INTEL_IOMMU
2008-10-17 23:14:13 +04:00
# ifdef CONFIG_SMP
2011-02-04 22:18:43 +03:00
static int dmar_msi_set_affinity ( struct irq_data * data ,
const struct cpumask * mask , bool force )
2008-10-17 23:14:13 +04:00
{
2011-02-04 22:18:43 +03:00
unsigned int irq = data - > irq ;
2008-10-17 23:14:13 +04:00
struct irq_cfg * cfg = irq_cfg + irq ;
struct msi_msg msg ;
2014-03-05 00:43:38 +04:00
int cpu = cpumask_first_and ( mask , cpu_online_mask ) ;
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 ) ;
2011-02-04 22:18:43 +03:00
cpumask_copy ( data - > 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 " ,
2010-09-28 19:15:11 +04:00
. irq_unmask = dmar_msi_unmask ,
. irq_mask = dmar_msi_mask ,
2011-02-04 22:18:43 +03:00
. irq_ack = ia64_ack_msi_irq ,
2008-10-17 23:14:13 +04:00
# ifdef CONFIG_SMP
2011-02-04 22:18:43 +03:00
. irq_set_affinity = dmar_msi_set_affinity ,
2008-10-17 23:14:13 +04:00
# endif
2011-02-04 22:18:43 +03:00
. irq_retrigger = ia64_msi_retrigger_irq ,
2008-10-17 23:14:13 +04: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-29 01:42:46 +04:00
cpumask_and ( & mask , & ( irq_to_domain ( irq ) ) , cpu_online_mask ) ;
2008-10-17 23:14:13 +04:00
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 ) ;
2011-03-25 23:06:09 +03:00
irq_set_chip_and_handler_name ( irq , & dmar_msi_type , handle_edge_irq ,
" edge " ) ;
2008-10-17 23:14:13 +04:00
return 0 ;
}
2011-08-24 04:05:25 +04:00
# endif /* CONFIG_INTEL_IOMMU */
2008-10-17 23:14:13 +04:00