]> err.no Git - linux-2.6/blobdiff - arch/powerpc/platforms/cell/pmu.c
Pull thermal into release branch
[linux-2.6] / arch / powerpc / platforms / cell / pmu.c
index 30d17ce236a7149dd35cd8b4033491dfdef69100..66ca4b5a1dbc6cab284962aec94ac9a38f2da189 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/interrupt.h>
 #include <linux/types.h>
 #include <asm/io.h>
+#include <asm/irq_regs.h>
 #include <asm/machdep.h>
+#include <asm/pmc.h>
 #include <asm/reg.h>
 #include <asm/spu.h>
 
 #include "cbe_regs.h"
 #include "interrupt.h"
-#include "pmu.h"
 
 /*
  * When writing to write-only mmio addresses, save a shadow copy. All of the
@@ -85,6 +87,7 @@ u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr)
 
        return val;
 }
+EXPORT_SYMBOL_GPL(cbe_read_phys_ctr);
 
 void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
 {
@@ -111,6 +114,7 @@ void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
                }
        }
 }
+EXPORT_SYMBOL_GPL(cbe_write_phys_ctr);
 
 /*
  * "Logical" counter registers.
@@ -130,6 +134,7 @@ u32 cbe_read_ctr(u32 cpu, u32 ctr)
 
        return val;
 }
+EXPORT_SYMBOL_GPL(cbe_read_ctr);
 
 void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
 {
@@ -149,6 +154,7 @@ void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
 
        cbe_write_phys_ctr(cpu, phys_ctr, val);
 }
+EXPORT_SYMBOL_GPL(cbe_write_ctr);
 
 /*
  * Counter-control registers.
@@ -164,12 +170,14 @@ u32 cbe_read_pm07_control(u32 cpu, u32 ctr)
 
        return pm07_control;
 }
+EXPORT_SYMBOL_GPL(cbe_read_pm07_control);
 
 void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
 {
        if (ctr < NR_CTRS)
                WRITE_WO_MMIO(pm07_control[ctr], val);
 }
+EXPORT_SYMBOL_GPL(cbe_write_pm07_control);
 
 /*
  * Other PMU control registers. Most of these are write-only.
@@ -215,6 +223,7 @@ u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
 
        return val;
 }
+EXPORT_SYMBOL_GPL(cbe_read_pm);
 
 void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
 {
@@ -252,6 +261,7 @@ void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
                break;
        }
 }
+EXPORT_SYMBOL_GPL(cbe_write_pm);
 
 /*
  * Get/set the size of a physical counter to either 16 or 32 bits.
@@ -268,6 +278,7 @@ u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr)
 
        return size;
 }
+EXPORT_SYMBOL_GPL(cbe_get_ctr_size);
 
 void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
 {
@@ -287,6 +298,7 @@ void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
                cbe_write_pm(cpu, pm_control, pm_ctrl);
        }
 }
+EXPORT_SYMBOL_GPL(cbe_set_ctr_size);
 
 /*
  * Enable/disable the entire performance monitoring unit.
@@ -304,6 +316,7 @@ void cbe_enable_pm(u32 cpu)
        pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
        cbe_write_pm(cpu, pm_control, pm_ctrl);
 }
+EXPORT_SYMBOL_GPL(cbe_enable_pm);
 
 void cbe_disable_pm(u32 cpu)
 {
@@ -311,6 +324,7 @@ void cbe_disable_pm(u32 cpu)
        pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
        cbe_write_pm(cpu, pm_control, pm_ctrl);
 }
+EXPORT_SYMBOL_GPL(cbe_disable_pm);
 
 /*
  * Reading from the trace_buffer.
@@ -325,4 +339,88 @@ void cbe_read_trace_buffer(u32 cpu, u64 *buf)
        *buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
        *buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
 }
+EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);
+
+/*
+ * Enabling/disabling interrupts for the entire performance monitoring unit.
+ */
+
+u32 cbe_get_and_clear_pm_interrupts(u32 cpu)
+{
+       /* Reading pm_status clears the interrupt bits. */
+       return cbe_read_pm(cpu, pm_status);
+}
+EXPORT_SYMBOL_GPL(cbe_get_and_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_get_and_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)
+{
+       perf_irq(get_irq_regs());
+       return IRQ_HANDLED;
+}
+
+static int __init cbe_init_pm_irq(void)
+{
+       unsigned int irq;
+       int rc, node;
+
+       if (!machine_is(cell))
+               return 0;
+
+       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);
+
+void cbe_sync_irq(int node)
+{
+       unsigned int irq;
+
+       irq = irq_find_mapping(NULL,
+                              IIC_IRQ_IOEX_PMI
+                              | (node << IIC_IRQ_NODE_SHIFT));
+
+       if (irq == NO_IRQ) {
+               printk(KERN_WARNING "ERROR, unable to get existing irq %d " \
+               "for node %d\n", irq, node);
+               return;
+       }
+
+       synchronize_irq(irq);
+}
+EXPORT_SYMBOL_GPL(cbe_sync_irq);