@ -1,3 +1,5 @@
# define pr_fmt(fmt) "irq: " fmt
# include <linux/debugfs.h>
# include <linux/hardirq.h>
# include <linux/interrupt.h>
@ -56,14 +58,73 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
return domain ;
}
static void irq_domain_free ( struct irq_domain * domain )
{
of_node_put ( domain - > of_node ) ;
kfree ( domain ) ;
}
static void irq_domain_add ( struct irq_domain * domain )
{
mutex_lock ( & irq_domain_mutex ) ;
list_add ( & domain - > link , & irq_domain_list ) ;
mutex_unlock ( & irq_domain_mutex ) ;
pr_debug ( " irq: Allocated domain of type %d @0x%p \n " ,
pr_debug ( " Allocated domain of type %d @0x%p \n " ,
domain - > revmap_type , domain ) ;
}
/**
* irq_domain_remove ( ) - Remove an irq domain .
* @ domain : domain to remove
*
* This routine is used to remove an irq domain . The caller must ensure
* that all mappings within the domain have been disposed of prior to
* use , depending on the revmap type .
*/
void irq_domain_remove ( struct irq_domain * domain )
{
mutex_lock ( & irq_domain_mutex ) ;
switch ( domain - > revmap_type ) {
case IRQ_DOMAIN_MAP_LEGACY :
/*
* Legacy domains don ' t manage their own irq_desc
* allocations , we expect the caller to handle irq_desc
* freeing on their own .
*/
break ;
case IRQ_DOMAIN_MAP_TREE :
/*
* radix_tree_delete ( ) takes care of destroying the root
* node when all entries are removed . Shout if there are
* any mappings left .
*/
WARN_ON ( domain - > revmap_data . tree . height ) ;
break ;
case IRQ_DOMAIN_MAP_LINEAR :
kfree ( domain - > revmap_data . linear . revmap ) ;
domain - > revmap_data . linear . size = 0 ;
break ;
case IRQ_DOMAIN_MAP_NOMAP :
break ;
}
list_del ( & domain - > link ) ;
/*
* If the going away domain is the default one , reset it .
*/
if ( unlikely ( irq_default_domain = = domain ) )
irq_set_default_host ( NULL ) ;
mutex_unlock ( & irq_domain_mutex ) ;
pr_debug ( " Removed domain of type %d @0x%p \n " ,
domain - > revmap_type , domain ) ;
irq_domain_free ( domain ) ;
}
EXPORT_SYMBOL_GPL ( irq_domain_remove ) ;
static unsigned int irq_domain_legacy_revmap ( struct irq_domain * domain ,
irq_hw_number_t hwirq )
@ -117,8 +178,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
if ( WARN_ON ( ! irq_data | | irq_data - > domain ) ) {
mutex_unlock ( & irq_domain_mutex ) ;
of_node_put ( domain - > of_node ) ;
kfree ( domain ) ;
irq_domain_free ( domain ) ;
return NULL ;
}
}
@ -152,10 +212,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
irq_domain_add ( domain ) ;
return domain ;
}
EXPORT_SYMBOL_GPL ( irq_domain_add_legacy ) ;
/**
* irq_domain_add_linear ( ) - Allocate and register a legacy revmap irq_domain .
* @ of_node : pointer to interrupt controller ' s device tree node .
* @ size : Number of interrupts in the domain .
* @ ops : map / unmap domain callbacks
* @ host_data : Controller private data pointer
*/
@ -181,6 +243,7 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
irq_domain_add ( domain ) ;
return domain ;
}
EXPORT_SYMBOL_GPL ( irq_domain_add_linear ) ;
struct irq_domain * irq_domain_add_nomap ( struct device_node * of_node ,
unsigned int max_irq ,
@ -195,6 +258,7 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
}
return domain ;
}
EXPORT_SYMBOL_GPL ( irq_domain_add_nomap ) ;
/**
* irq_domain_add_tree ( )
@ -216,6 +280,7 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
}
return domain ;
}
EXPORT_SYMBOL_GPL ( irq_domain_add_tree ) ;
/**
* irq_find_host ( ) - Locates a domain for a given device node
@ -259,10 +324,11 @@ EXPORT_SYMBOL_GPL(irq_find_host);
*/
void irq_set_default_host ( struct irq_domain * domain )
{
pr_debug ( " irq: Default domain set to @0x%p\n " , domain ) ;
pr_debug ( " Default domain set to @0x%p \n " , domain ) ;
irq_default_domain = domain ;
}
EXPORT_SYMBOL_GPL ( irq_set_default_host ) ;
static int irq_setup_virq ( struct irq_domain * domain , unsigned int virq ,
irq_hw_number_t hwirq )
@ -272,7 +338,7 @@ static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
irq_data - > hwirq = hwirq ;
irq_data - > domain = domain ;
if ( domain - > ops - > map ( domain , virq , hwirq ) ) {
pr_debug ( " irq: -> mapping failed, freeing \n " ) ;
pr_debug ( " irq-%i== >hwirq-0x%lx mapping failed \n " , virq , hwirq ) ;
irq_data - > domain = NULL ;
irq_data - > hwirq = 0 ;
return - 1 ;
@ -303,7 +369,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
virq = irq_alloc_desc_from ( 1 , 0 ) ;
if ( ! virq ) {
pr_debug ( " irq: create_direct virq allocation failed\n " ) ;
pr_debug ( " create_direct virq allocation failed \n " ) ;
return 0 ;
}
if ( virq > = domain - > revmap_data . nomap . max_irq ) {
@ -312,7 +378,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
irq_free_desc ( virq ) ;
return 0 ;
}
pr_debug ( " irq: create_direct obtained virq %d\n " , virq ) ;
pr_debug ( " create_direct obtained virq %d \n " , virq ) ;
if ( irq_setup_virq ( domain , virq , virq ) ) {
irq_free_desc ( virq ) ;
@ -321,6 +387,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
return virq ;
}
EXPORT_SYMBOL_GPL ( irq_create_direct_mapping ) ;
/**
* irq_create_mapping ( ) - Map a hardware interrupt into linux irq space
@ -338,23 +405,23 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
unsigned int hint ;
int virq ;
pr_debug ( " irq: irq _create_mapping(0x%p, 0x%lx) \n " , domain , hwirq ) ;
pr_debug ( " irq_create_mapping(0x%p, 0x%lx) \n " , domain , hwirq ) ;
/* Look for default domain if nececssary */
if ( domain = = NULL )
domain = irq_default_domain ;
if ( domain = = NULL ) {
printk ( KERN_WARNING " irq_create_mapping called for "
" NULL domain, hwirq=%lx \n " , hwirq ) ;
pr_warning ( " irq_create_mapping called for "
" NULL domain, hwirq=%lx \n " , hwirq ) ;
WARN_ON ( 1 ) ;
return 0 ;
}
pr_debug ( " irq: -> using domain @%p\n " , domain ) ;
pr_debug ( " -> using domain @%p \n " , domain ) ;
/* Check if mapping already exists */
virq = irq_find_mapping ( domain , hwirq ) ;
if ( virq ) {
pr_debug ( " irq: -> existing mapping on virq %d\n " , virq ) ;
pr_debug ( " -> existing mapping on virq %d \n " , virq ) ;
return virq ;
}
@ -370,7 +437,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
if ( virq < = 0 )
virq = irq_alloc_desc_from ( 1 , 0 ) ;
if ( virq < = 0 ) {
pr_debug ( " irq: -> virq allocation failed\n " ) ;
pr_debug ( " -> virq allocation failed \n " ) ;
return 0 ;
}
@ -380,7 +447,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
return 0 ;
}
pr_debug ( " irq: irq %lu on domain %s mapped to virtual irq %u \n " ,
pr_debug ( " irq %lu on domain %s mapped to virtual irq %u \n " ,
hwirq , domain - > of_node ? domain - > of_node - > full_name : " null " , virq ) ;
return virq ;
@ -409,8 +476,8 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
if ( intsize > 0 )
return intspec [ 0 ] ;
# endif
printk ( KERN_WARNING " irq: no irq domain found for %s !\n " ,
controller - > full_name ) ;
pr_warning ( " no irq domain found for %s ! \n " ,
controller - > full_name ) ;
return 0 ;
}
@ -560,6 +627,7 @@ unsigned int irq_radix_revmap_lookup(struct irq_domain *domain,
*/
return irq_data ? irq_data - > irq : irq_find_mapping ( domain , hwirq ) ;
}
EXPORT_SYMBOL_GPL ( irq_radix_revmap_lookup ) ;
/**
* irq_radix_revmap_insert ( ) - Insert a hw irq to linux irq number mapping .
@ -584,6 +652,7 @@ void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq,
mutex_unlock ( & revmap_trees_mutex ) ;
}
}
EXPORT_SYMBOL_GPL ( irq_radix_revmap_insert ) ;
/**
* irq_linear_revmap ( ) - Find a linux irq from a hw irq number .
@ -617,6 +686,7 @@ unsigned int irq_linear_revmap(struct irq_domain *domain,
return revmap [ hwirq ] ;
}
EXPORT_SYMBOL_GPL ( irq_linear_revmap ) ;
# ifdef CONFIG_IRQ_DOMAIN_DEBUG
static int virq_debug_show ( struct seq_file * m , void * private )
@ -691,8 +761,8 @@ static int __init irq_debugfs_init(void)
__initcall ( irq_debugfs_init ) ;
# endif /* CONFIG_IRQ_DOMAIN_DEBUG */
int irq_domain_simple_map ( struct irq_domain * d , unsigned int irq ,
irq_hw_number_t hwirq )
static int irq_domain_simple_map ( struct irq_domain * d , unsigned int irq ,
irq_hw_number_t hwirq )
{
return 0 ;
}