Commit 0443bbd3 authored by Kevin Corry's avatar Kevin Corry Committed by Paul Mackerras

[POWERPC] cell: Add routines for managing PMU interrupts

The following routines are added to arch/powerpc/platforms/cell/pmu.c:
 cbe_clear_pm_interrupts()
 cbe_enable_pm_interrupts()
 cbe_disable_pm_interrupts()
 cbe_query_pm_interrupts()
 cbe_pm_irq()
 cbe_init_pm_irq()

This also adds a routine in arch/powerpc/platforms/cell/interrupt.c and
some macros in cbe_regs.h to manipulate the IIC_IR register:
 iic_set_interrupt_routing()
Signed-off-by: default avatarKevin Corry <kevcorry@us.ibm.com>
Signed-off-by: default avatarCarl Love <carll@us.ibm.com>
Signed-off-by: default avatarArnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent e4f6948c
...@@ -185,6 +185,14 @@ struct cbe_iic_regs { ...@@ -185,6 +185,14 @@ struct cbe_iic_regs {
struct cbe_iic_thread_regs thread[2]; /* 0x0400 */ struct cbe_iic_thread_regs thread[2]; /* 0x0400 */
u64 iic_ir; /* 0x0440 */ u64 iic_ir; /* 0x0440 */
#define CBE_IIC_IR_PRIO(x) (((x) & 0xf) << 12)
#define CBE_IIC_IR_DEST_NODE(x) (((x) & 0xf) << 4)
#define CBE_IIC_IR_DEST_UNIT(x) ((x) & 0xf)
#define CBE_IIC_IR_IOC_0 0x0
#define CBE_IIC_IR_IOC_1S 0xb
#define CBE_IIC_IR_PT_0 0xe
#define CBE_IIC_IR_PT_1 0xf
u64 iic_is; /* 0x0448 */ u64 iic_is; /* 0x0448 */
#define CBE_IIC_IS_PMI 0x2 #define CBE_IIC_IS_PMI 0x2
......
...@@ -396,3 +396,19 @@ void __init iic_init_IRQ(void) ...@@ -396,3 +396,19 @@ void __init iic_init_IRQ(void)
/* Enable on current CPU */ /* Enable on current CPU */
iic_setup_cpu(); iic_setup_cpu();
} }
void iic_set_interrupt_routing(int cpu, int thread, int priority)
{
struct cbe_iic_regs __iomem *iic_regs = cbe_get_cpu_iic_regs(cpu);
u64 iic_ir = 0;
int node = cpu >> 1;
/* Set which node and thread will handle the next interrupt */
iic_ir |= CBE_IIC_IR_PRIO(priority) |
CBE_IIC_IR_DEST_NODE(node);
if (thread == 0)
iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_0);
else
iic_ir |= CBE_IIC_IR_DEST_UNIT(CBE_IIC_IR_PT_1);
out_be64(&iic_regs->iic_ir, iic_ir);
}
...@@ -83,5 +83,7 @@ extern u8 iic_get_target_id(int cpu); ...@@ -83,5 +83,7 @@ extern u8 iic_get_target_id(int cpu);
extern void spider_init_IRQ(void); extern void spider_init_IRQ(void);
extern void iic_set_interrupt_routing(int cpu, int thread, int priority);
#endif #endif
#endif /* ASM_CELL_PIC_H */ #endif /* ASM_CELL_PIC_H */
...@@ -22,9 +22,11 @@ ...@@ -22,9 +22,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/interrupt.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/pmc.h>
#include <asm/reg.h> #include <asm/reg.h>
#include <asm/spu.h> #include <asm/spu.h>
...@@ -338,3 +340,71 @@ void cbe_read_trace_buffer(u32 cpu, u64 *buf) ...@@ -338,3 +340,71 @@ void cbe_read_trace_buffer(u32 cpu, u64 *buf)
} }
EXPORT_SYMBOL_GPL(cbe_read_trace_buffer); EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);
/*
* Enabling/disabling interrupts for the entire performance monitoring unit.
*/
u32 cbe_query_pm_interrupts(u32 cpu)
{
return cbe_read_pm(cpu, pm_status);
}
EXPORT_SYMBOL_GPL(cbe_query_pm_interrupts);
u32 cbe_clear_pm_interrupts(u32 cpu)
{
/* Reading pm_status clears the interrupt bits. */
return cbe_query_pm_interrupts(cpu);
}
EXPORT_SYMBOL_GPL(cbe_clear_pm_interrupts);
void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
{
/* Set which node and thread will handle the next interrupt. */
iic_set_interrupt_routing(cpu, thread, 0);
/* Enable the interrupt bits in the pm_status register. */
if (mask)
cbe_write_pm(cpu, pm_status, mask);
}
EXPORT_SYMBOL_GPL(cbe_enable_pm_interrupts);
void cbe_disable_pm_interrupts(u32 cpu)
{
cbe_clear_pm_interrupts(cpu);
cbe_write_pm(cpu, pm_status, 0);
}
EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts);
static irqreturn_t cbe_pm_irq(int irq, void *dev_id, struct pt_regs *regs)
{
perf_irq(regs);
return IRQ_HANDLED;
}
int __init cbe_init_pm_irq(void)
{
unsigned int irq;
int rc, node;
for_each_node(node) {
irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
(node << IIC_IRQ_NODE_SHIFT));
if (irq == NO_IRQ) {
printk("ERROR: Unable to allocate irq for node %d\n",
node);
return -EINVAL;
}
rc = request_irq(irq, cbe_pm_irq,
IRQF_DISABLED, "cbe-pmu-0", NULL);
if (rc) {
printk("ERROR: Request for irq on node %d failed\n",
node);
return rc;
}
}
return 0;
}
arch_initcall(cbe_init_pm_irq);
...@@ -87,4 +87,9 @@ extern void cbe_disable_pm(u32 cpu); ...@@ -87,4 +87,9 @@ extern void cbe_disable_pm(u32 cpu);
extern void cbe_read_trace_buffer(u32 cpu, u64 *buf); extern void cbe_read_trace_buffer(u32 cpu, u64 *buf);
extern void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask);
extern void cbe_disable_pm_interrupts(u32 cpu);
extern u32 cbe_query_pm_interrupts(u32 cpu);
extern u32 cbe_clear_pm_interrupts(u32 cpu);
#endif /* __ASM_CELL_PMU_H__ */ #endif /* __ASM_CELL_PMU_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment