2007-01-24 22:41:24 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/stddef.h>
# include <linux/init.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 ) ;
static struct irq_host * mpc8xx_pic_host ;
# define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
static unsigned long ppc_cached_irq_mask [ NR_MASK_WORDS ] ;
2007-09-14 23:22:36 +04:00
static sysconf8xx_t __iomem * siu_reg ;
2007-01-24 22:41:24 +03:00
int cpm_get_irq ( struct pt_regs * regs ) ;
static void mpc8xx_unmask_irq ( unsigned int virq )
{
int bit , word ;
unsigned int irq_nr = ( unsigned int ) irq_map [ virq ] . hwirq ;
bit = irq_nr & 0x1f ;
word = irq_nr > > 5 ;
ppc_cached_irq_mask [ word ] | = ( 1 < < ( 31 - bit ) ) ;
out_be32 ( & siu_reg - > sc_simask , ppc_cached_irq_mask [ word ] ) ;
}
static void mpc8xx_mask_irq ( unsigned int virq )
{
int bit , word ;
unsigned int irq_nr = ( unsigned int ) irq_map [ virq ] . hwirq ;
bit = irq_nr & 0x1f ;
word = irq_nr > > 5 ;
ppc_cached_irq_mask [ word ] & = ~ ( 1 < < ( 31 - bit ) ) ;
out_be32 ( & siu_reg - > sc_simask , ppc_cached_irq_mask [ word ] ) ;
}
static void mpc8xx_ack ( unsigned int virq )
{
int bit ;
unsigned int irq_nr = ( unsigned int ) irq_map [ virq ] . hwirq ;
bit = irq_nr & 0x1f ;
out_be32 ( & siu_reg - > sc_sipend , 1 < < ( 31 - bit ) ) ;
}
static void mpc8xx_end_irq ( unsigned int virq )
{
int bit , word ;
unsigned int irq_nr = ( unsigned int ) irq_map [ virq ] . hwirq ;
bit = irq_nr & 0x1f ;
word = irq_nr > > 5 ;
ppc_cached_irq_mask [ word ] | = ( 1 < < ( 31 - bit ) ) ;
out_be32 ( & siu_reg - > sc_simask , ppc_cached_irq_mask [ word ] ) ;
}
static int mpc8xx_set_irq_type ( unsigned int virq , unsigned int flow_type )
{
struct irq_desc * desc = get_irq_desc ( virq ) ;
desc - > status & = ~ ( IRQ_TYPE_SENSE_MASK | IRQ_LEVEL ) ;
desc - > status | = flow_type & IRQ_TYPE_SENSE_MASK ;
if ( flow_type & ( IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW ) )
desc - > status | = IRQ_LEVEL ;
if ( flow_type & IRQ_TYPE_EDGE_FALLING ) {
irq_hw_number_t hw = ( unsigned int ) irq_map [ virq ] . hwirq ;
unsigned int siel = in_be32 ( & siu_reg - > sc_siel ) ;
/* only external IRQ senses are programmable */
if ( ( hw & 1 ) = = 0 ) {
siel | = ( 0x80000000 > > hw ) ;
out_be32 ( & siu_reg - > sc_siel , siel ) ;
desc - > handle_irq = handle_edge_irq ;
}
}
return 0 ;
}
static struct irq_chip mpc8xx_pic = {
. typename = " MPC8XX SIU " ,
. unmask = mpc8xx_unmask_irq ,
. mask = mpc8xx_mask_irq ,
. ack = mpc8xx_ack ,
. eoi = mpc8xx_end_irq ,
. set_type = mpc8xx_set_irq_type ,
} ;
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 ) ;
}
static int mpc8xx_pic_host_map ( struct irq_host * h , unsigned int virq ,
irq_hw_number_t hw )
{
pr_debug ( " mpc8xx_pic_host_map(%d, 0x%lx) \n " , virq , hw ) ;
/* Set default irq handle */
set_irq_chip_and_handler ( virq , & mpc8xx_pic , handle_level_irq ) ;
return 0 ;
}
static int mpc8xx_pic_host_xlate ( struct irq_host * h , struct device_node * ct ,
u32 * intspec , unsigned int intsize ,
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 ,
} ;
* 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 ;
}
static struct irq_host_ops mpc8xx_pic_host_ops = {
. map = mpc8xx_pic_host_map ,
. xlate = mpc8xx_pic_host_xlate ,
} ;
int mpc8xx_pic_init ( void )
{
struct resource res ;
2007-09-14 23:22:36 +04:00
struct device_node * np ;
2007-01-24 22:41:24 +03:00
int ret ;
2007-09-14 23:22:36 +04: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 23:22:36 +04: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 12:47:54 +04:00
goto out ;
2007-01-24 22:41:24 +03:00
2007-09-14 23:22:36 +04:00
siu_reg = ioremap ( res . start , res . end - res . start + 1 ) ;
[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-05 10:34:59 +03:00
if ( siu_reg = = NULL ) {
ret = - EINVAL ;
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-05 10:34:59 +03:00
mpc8xx_pic_host = irq_alloc_host ( np , IRQ_HOST_MAP_LINEAR ,
2007-08-28 12:47:54 +04:00
64 , & mpc8xx_pic_host_ops , 64 ) ;
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-05 10:34:59 +03: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-05 10:34:59 +03:00
return 0 ;
2007-01-24 22:41:24 +03:00
2007-08-28 12:47:54 +04:00
out :
of_node_put ( np ) ;
2007-01-24 22:41:24 +03:00
return ret ;
}