@ -57,6 +57,7 @@
/**
* struct vic_device - VIC PM device
* @ parent_irq : The parent IRQ number of the VIC if cascaded , or 0.
* @ irq : The IRQ number for the base of the VIC .
* @ base : The register base for the VIC .
* @ valid_sources : A bitmask of valid interrupts
@ -224,6 +225,17 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
return handled ;
}
static void vic_handle_irq_cascaded ( unsigned int irq , struct irq_desc * desc )
{
u32 stat , hwirq ;
struct vic_device * vic = irq_desc_get_handler_data ( desc ) ;
while ( ( stat = readl_relaxed ( vic - > base + VIC_IRQ_STATUS ) ) ) {
hwirq = ffs ( stat ) - 1 ;
generic_handle_irq ( irq_find_mapping ( vic - > domain , hwirq ) ) ;
}
}
/*
* Keep iterating over all registered VIC ' s until there are no pending
* interrupts .
@ -246,6 +258,7 @@ static struct irq_domain_ops vic_irqdomain_ops = {
/**
* vic_register ( ) - Register a VIC .
* @ base : The base address of the VIC .
* @ parent_irq : The parent IRQ if cascaded , else 0.
* @ irq : The base IRQ for the VIC .
* @ valid_sources : bitmask of valid interrupts
* @ resume_sources : bitmask of interrupts allowed for resume sources .
@ -257,7 +270,8 @@ static struct irq_domain_ops vic_irqdomain_ops = {
*
* This also configures the IRQ domain for the VIC .
*/
static void __init vic_register ( void __iomem * base , unsigned int irq ,
static void __init vic_register ( void __iomem * base , unsigned int parent_irq ,
unsigned int irq ,
u32 valid_sources , u32 resume_sources ,
struct device_node * node )
{
@ -275,6 +289,12 @@ static void __init vic_register(void __iomem *base, unsigned int irq,
v - > resume_sources = resume_sources ;
set_handle_irq ( vic_handle_irq ) ;
vic_id + + ;
if ( parent_irq ) {
irq_set_handler_data ( parent_irq , v ) ;
irq_set_chained_handler ( parent_irq , vic_handle_irq_cascaded ) ;
}
v - > domain = irq_domain_add_simple ( node , fls ( valid_sources ) , irq ,
& vic_irqdomain_ops , v ) ;
/* create an IRQ mapping for each valid IRQ */
@ -413,10 +433,10 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
writel ( 32 , base + VIC_PL190_DEF_VECT_ADDR ) ;
}
vic_register ( base , irq_start , vic_sources , 0 , node ) ;
vic_register ( base , 0 , irq_start , vic_sources , 0 , node ) ;
}
void __init __vic_init ( void __iomem * base , int irq_start ,
void __init __vic_init ( void __iomem * base , int parent_irq , int irq_start ,
u32 vic_sources , u32 resume_sources ,
struct device_node * node )
{
@ -453,7 +473,7 @@ void __init __vic_init(void __iomem *base, int irq_start,
vic_init2 ( base ) ;
vic_register ( base , irq_start , vic_sources , resume_sources , node ) ;
vic_register ( base , parent_irq , irq_start , vic_sources , resume_sources , node ) ;
}
/**
@ -466,7 +486,28 @@ void __init __vic_init(void __iomem *base, int irq_start,
void __init vic_init ( void __iomem * base , unsigned int irq_start ,
u32 vic_sources , u32 resume_sources )
{
__vic_init ( base , irq_start , vic_sources , resume_sources , NULL ) ;
__vic_init ( base , 0 , irq_start , vic_sources , resume_sources , NULL ) ;
}
/**
* vic_init_cascaded ( ) - initialise a cascaded vectored interrupt controller
* @ base : iomem base address
* @ parent_irq : the parent IRQ we ' re cascaded off
* @ irq_start : starting interrupt number , must be muliple of 32
* @ vic_sources : bitmask of interrupt sources to allow
* @ resume_sources : bitmask of interrupt sources to allow for resume
*
* This returns the base for the new interrupts or negative on error .
*/
int __init vic_init_cascaded ( void __iomem * base , unsigned int parent_irq ,
u32 vic_sources , u32 resume_sources )
{
struct vic_device * v ;
v = & vic_devices [ vic_id ] ;
__vic_init ( base , parent_irq , 0 , vic_sources , resume_sources , NULL ) ;
/* Return out acquired base */
return v - > irq ;
}
# ifdef CONFIG_OF
@ -489,7 +530,7 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
/*
* Passing 0 as first IRQ makes the simple domain allocate descriptors
*/
__vic_init ( regs , 0 , interrupt_mask , wakeup_mask , node ) ;
__vic_init ( regs , 0 , 0 , interrupt_mask , wakeup_mask , node ) ;
return 0 ;
}