2007-01-24 22:41:24 +03:00
# include <linux/kernel.h>
# include <linux/stddef.h>
# include <linux/sched.h>
# include <linux/signal.h>
# include <linux/irq.h>
# include <linux/dma-mapping.h>
# include <asm/prom.h>
# include <asm/irq.h>
# include <asm/io.h>
# include <asm/8xx_immap.h>
# include "mpc8xx_pic.h"
# define PIC_VEC_SPURRIOUS 15
extern int cpm_get_irq ( struct pt_regs * regs ) ;
2012-02-14 14:06:50 -07:00
static struct irq_domain * mpc8xx_pic_host ;
2012-04-23 12:30:01 +00:00
static unsigned long mpc8xx_cached_irq_mask ;
2007-09-14 14:22:36 -05:00
static sysconf8xx_t __iomem * siu_reg ;
2007-01-24 22:41:24 +03:00
2012-04-23 12:30:01 +00:00
static inline unsigned long mpc8xx_irqd_to_bit ( struct irq_data * d )
{
return 0x80000000 > > irqd_to_hwirq ( d ) ;
}
2007-01-24 22:41:24 +03:00
2011-03-07 14:00:00 +00:00
static void mpc8xx_unmask_irq ( struct irq_data * d )
2007-01-24 22:41:24 +03:00
{
2012-04-23 12:30:01 +00:00
mpc8xx_cached_irq_mask | = mpc8xx_irqd_to_bit ( d ) ;
out_be32 ( & siu_reg - > sc_simask , mpc8xx_cached_irq_mask ) ;
2007-01-24 22:41:24 +03:00
}
2011-03-07 14:00:00 +00:00
static void mpc8xx_mask_irq ( struct irq_data * d )
2007-01-24 22:41:24 +03:00
{
2012-04-23 12:30:01 +00:00
mpc8xx_cached_irq_mask & = ~ mpc8xx_irqd_to_bit ( d ) ;
out_be32 ( & siu_reg - > sc_simask , mpc8xx_cached_irq_mask ) ;
2007-01-24 22:41:24 +03:00
}
2011-03-07 14:00:00 +00:00
static void mpc8xx_ack ( struct irq_data * d )
2007-01-24 22:41:24 +03:00
{
2012-04-23 12:30:01 +00:00
out_be32 ( & siu_reg - > sc_sipend , mpc8xx_irqd_to_bit ( d ) ) ;
2007-01-24 22:41:24 +03:00
}
2011-03-07 14:00:00 +00:00
static void mpc8xx_end_irq ( struct irq_data * d )
2007-01-24 22:41:24 +03:00
{
2012-04-23 12:30:01 +00:00
mpc8xx_cached_irq_mask | = mpc8xx_irqd_to_bit ( d ) ;
out_be32 ( & siu_reg - > sc_simask , mpc8xx_cached_irq_mask ) ;
2007-01-24 22:41:24 +03:00
}
2011-03-07 14:00:00 +00:00
static int mpc8xx_set_irq_type ( struct irq_data * d , unsigned int flow_type )
2007-01-24 22:41:24 +03:00
{
2012-04-23 12:30:01 +00:00
/* only external IRQ senses are programmable */
if ( ( flow_type & IRQ_TYPE_EDGE_FALLING ) & & ! ( irqd_to_hwirq ( d ) & 1 ) ) {
2007-01-24 22:41:24 +03:00
unsigned int siel = in_be32 ( & siu_reg - > sc_siel ) ;
2012-04-23 12:30:01 +00:00
siel | = mpc8xx_irqd_to_bit ( d ) ;
out_be32 ( & siu_reg - > sc_siel , siel ) ;
__irq_set_handler_locked ( d - > irq , handle_edge_irq ) ;
2007-01-24 22:41:24 +03:00
}
return 0 ;
}
static struct irq_chip mpc8xx_pic = {
2010-01-31 20:33:41 +00:00
. name = " MPC8XX SIU " ,
2011-03-07 14:00:00 +00:00
. irq_unmask = mpc8xx_unmask_irq ,
. irq_mask = mpc8xx_mask_irq ,
. irq_ack = mpc8xx_ack ,
. irq_eoi = mpc8xx_end_irq ,
. irq_set_type = mpc8xx_set_irq_type ,
2007-01-24 22:41:24 +03:00
} ;
unsigned int mpc8xx_get_irq ( void )
{
int irq ;
/* For MPC8xx, read the SIVEC register and shift the bits down
* to get the irq number .
*/
irq = in_be32 ( & siu_reg - > sc_sivec ) > > 26 ;
if ( irq = = PIC_VEC_SPURRIOUS )
irq = NO_IRQ ;
return irq_linear_revmap ( mpc8xx_pic_host , irq ) ;
}
2012-02-14 14:06:50 -07:00
static int mpc8xx_pic_host_map ( struct irq_domain * h , unsigned int virq ,
2007-01-24 22:41:24 +03:00
irq_hw_number_t hw )
{
pr_debug ( " mpc8xx_pic_host_map(%d, 0x%lx) \n " , virq , hw ) ;
/* Set default irq handle */
2011-03-25 16:45:20 +01:00
irq_set_chip_and_handler ( virq , & mpc8xx_pic , handle_level_irq ) ;
2007-01-24 22:41:24 +03:00
return 0 ;
}
2012-02-14 14:06:50 -07:00
static int mpc8xx_pic_host_xlate ( struct irq_domain * h , struct device_node * ct ,
2009-12-08 02:39:50 +00:00
const u32 * intspec , unsigned int intsize ,
2007-01-24 22:41:24 +03:00
irq_hw_number_t * out_hwirq , unsigned int * out_flags )
{
static unsigned char map_pic_senses [ 4 ] = {
IRQ_TYPE_EDGE_RISING ,
IRQ_TYPE_LEVEL_LOW ,
IRQ_TYPE_LEVEL_HIGH ,
IRQ_TYPE_EDGE_FALLING ,
} ;
2012-04-23 12:30:01 +00:00
if ( intspec [ 0 ] > 0x1f )
return 0 ;
2007-01-24 22:41:24 +03:00
* out_hwirq = intspec [ 0 ] ;
if ( intsize > 1 & & intspec [ 1 ] < 4 )
* out_flags = map_pic_senses [ intspec [ 1 ] ] ;
else
* out_flags = IRQ_TYPE_NONE ;
return 0 ;
}
2012-02-14 14:06:50 -07:00
static struct irq_domain_ops mpc8xx_pic_host_ops = {
2007-01-24 22:41:24 +03:00
. map = mpc8xx_pic_host_map ,
. xlate = mpc8xx_pic_host_xlate ,
} ;
int mpc8xx_pic_init ( void )
{
struct resource res ;
2007-09-14 14:22:36 -05:00
struct device_node * np ;
2007-01-24 22:41:24 +03:00
int ret ;
2007-09-14 14:22:36 -05:00
np = of_find_compatible_node ( NULL , NULL , " fsl,pq1-pic " ) ;
if ( np = = NULL )
np = of_find_node_by_type ( NULL , " mpc8xx-pic " ) ;
2007-01-24 22:41:24 +03:00
if ( np = = NULL ) {
2007-09-14 14:22:36 -05:00
printk ( KERN_ERR " Could not find fsl,pq1-pic node \n " ) ;
2007-01-24 22:41:24 +03:00
return - ENOMEM ;
}
ret = of_address_to_resource ( np , 0 , & res ) ;
if ( ret )
2007-08-28 18:47:54 +10:00
goto out ;
2007-01-24 22:41:24 +03:00
2011-06-09 09:13:32 -07:00
siu_reg = ioremap ( res . start , resource_size ( & res ) ) ;
[POWERPC] arch/powerpc/sysdev: Add missing of_node_put
The functions of_find_compatible_node and of_find_node_by_type both
call of_node_get on their result. So any error handling code
thereafter should call of_node_put(np). This is taken care of in the
case where there is a goto out, but not when there is a direct return.
The function irq_alloc_host puts np into the returned structure, which is
stored in the global variable mpc8xx_pic_host, so the reference count
should be set for the lifetime of that variable. The current solution ups
the reference count again in the argument to irq_alloc_host so that it can
be decremented on the way out. This seems a bit unnecessary, and also
doesn't work in the case where irq_alloc_host fails, because then the
reference count only goes does by one, whereas it should go down by two. A
better solution is to not increment the reference count in the argument to
irq_alloc_host and only decrement it on the way out in an error case.
The problem was found using the following semantic match.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@@
type T,T1,T2;
identifier E;
statement S;
expression x1,x2,x3;
int ret;
@@
T E;
...
* E = \(of_get_parent\|of_find_compatible_node\)(...);
if (E == NULL) S
... when != of_node_put(...,(T1)E,...)
when != if (E != NULL) { ... of_node_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
if (...) {
... when != of_node_put(...,(T2)E,...)
when != if (E != NULL) { ... of_node_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
* return;
|
* return ret;
)
}
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@gate.crashing.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-02-04 23:34:59 -08:00
if ( siu_reg = = NULL ) {
ret = - EINVAL ;
goto out ;
}
2007-01-24 22:41:24 +03:00
2012-02-14 14:06:54 -07:00
mpc8xx_pic_host = irq_domain_add_linear ( np , 64 , & mpc8xx_pic_host_ops , NULL ) ;
2007-01-24 22:41:24 +03:00
if ( mpc8xx_pic_host = = NULL ) {
printk ( KERN_ERR " MPC8xx PIC: failed to allocate irq host! \n " ) ;
ret = - ENOMEM ;
[POWERPC] arch/powerpc/sysdev: Add missing of_node_put
The functions of_find_compatible_node and of_find_node_by_type both
call of_node_get on their result. So any error handling code
thereafter should call of_node_put(np). This is taken care of in the
case where there is a goto out, but not when there is a direct return.
The function irq_alloc_host puts np into the returned structure, which is
stored in the global variable mpc8xx_pic_host, so the reference count
should be set for the lifetime of that variable. The current solution ups
the reference count again in the argument to irq_alloc_host so that it can
be decremented on the way out. This seems a bit unnecessary, and also
doesn't work in the case where irq_alloc_host fails, because then the
reference count only goes does by one, whereas it should go down by two. A
better solution is to not increment the reference count in the argument to
irq_alloc_host and only decrement it on the way out in an error case.
The problem was found using the following semantic match.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@@
type T,T1,T2;
identifier E;
statement S;
expression x1,x2,x3;
int ret;
@@
T E;
...
* E = \(of_get_parent\|of_find_compatible_node\)(...);
if (E == NULL) S
... when != of_node_put(...,(T1)E,...)
when != if (E != NULL) { ... of_node_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
if (...) {
... when != of_node_put(...,(T2)E,...)
when != if (E != NULL) { ... of_node_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
* return;
|
* return ret;
)
}
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@gate.crashing.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-02-04 23:34:59 -08:00
goto out ;
2007-01-24 22:41:24 +03:00
}
[POWERPC] arch/powerpc/sysdev: Add missing of_node_put
The functions of_find_compatible_node and of_find_node_by_type both
call of_node_get on their result. So any error handling code
thereafter should call of_node_put(np). This is taken care of in the
case where there is a goto out, but not when there is a direct return.
The function irq_alloc_host puts np into the returned structure, which is
stored in the global variable mpc8xx_pic_host, so the reference count
should be set for the lifetime of that variable. The current solution ups
the reference count again in the argument to irq_alloc_host so that it can
be decremented on the way out. This seems a bit unnecessary, and also
doesn't work in the case where irq_alloc_host fails, because then the
reference count only goes does by one, whereas it should go down by two. A
better solution is to not increment the reference count in the argument to
irq_alloc_host and only decrement it on the way out in an error case.
The problem was found using the following semantic match.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@@
type T,T1,T2;
identifier E;
statement S;
expression x1,x2,x3;
int ret;
@@
T E;
...
* E = \(of_get_parent\|of_find_compatible_node\)(...);
if (E == NULL) S
... when != of_node_put(...,(T1)E,...)
when != if (E != NULL) { ... of_node_put(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
if (...) {
... when != of_node_put(...,(T2)E,...)
when != if (E != NULL) { ... of_node_put(...,(T2)E,...); ...}
when != x2 = (T2)E
(
* return;
|
* return ret;
)
}
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@gate.crashing.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2008-02-04 23:34:59 -08:00
return 0 ;
2007-01-24 22:41:24 +03:00
2007-08-28 18:47:54 +10:00
out :
of_node_put ( np ) ;
2007-01-24 22:41:24 +03:00
return ret ;
}