root/arch/powerpc/platforms/cell/pmu.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cbe_read_phys_ctr
  2. cbe_write_phys_ctr
  3. cbe_read_ctr
  4. cbe_write_ctr
  5. cbe_read_pm07_control
  6. cbe_write_pm07_control
  7. cbe_read_pm
  8. cbe_write_pm
  9. cbe_get_ctr_size
  10. cbe_set_ctr_size
  11. cbe_enable_pm
  12. cbe_disable_pm
  13. cbe_read_trace_buffer
  14. cbe_get_and_clear_pm_interrupts
  15. cbe_enable_pm_interrupts
  16. cbe_disable_pm_interrupts
  17. cbe_pm_irq
  18. cbe_init_pm_irq
  19. cbe_sync_irq

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Cell Broadband Engine Performance Monitor
   4  *
   5  * (C) Copyright IBM Corporation 2001,2006
   6  *
   7  * Author:
   8  *    David Erb (djerb@us.ibm.com)
   9  *    Kevin Corry (kevcorry@us.ibm.com)
  10  */
  11 
  12 #include <linux/interrupt.h>
  13 #include <linux/types.h>
  14 #include <linux/export.h>
  15 #include <asm/io.h>
  16 #include <asm/irq_regs.h>
  17 #include <asm/machdep.h>
  18 #include <asm/pmc.h>
  19 #include <asm/reg.h>
  20 #include <asm/spu.h>
  21 #include <asm/cell-regs.h>
  22 
  23 #include "interrupt.h"
  24 
  25 /*
  26  * When writing to write-only mmio addresses, save a shadow copy. All of the
  27  * registers are 32-bit, but stored in the upper-half of a 64-bit field in
  28  * pmd_regs.
  29  */
  30 
  31 #define WRITE_WO_MMIO(reg, x)                                   \
  32         do {                                                    \
  33                 u32 _x = (x);                                   \
  34                 struct cbe_pmd_regs __iomem *pmd_regs;          \
  35                 struct cbe_pmd_shadow_regs *shadow_regs;        \
  36                 pmd_regs = cbe_get_cpu_pmd_regs(cpu);           \
  37                 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
  38                 out_be64(&(pmd_regs->reg), (((u64)_x) << 32));  \
  39                 shadow_regs->reg = _x;                          \
  40         } while (0)
  41 
  42 #define READ_SHADOW_REG(val, reg)                               \
  43         do {                                                    \
  44                 struct cbe_pmd_shadow_regs *shadow_regs;        \
  45                 shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu); \
  46                 (val) = shadow_regs->reg;                       \
  47         } while (0)
  48 
  49 #define READ_MMIO_UPPER32(val, reg)                             \
  50         do {                                                    \
  51                 struct cbe_pmd_regs __iomem *pmd_regs;          \
  52                 pmd_regs = cbe_get_cpu_pmd_regs(cpu);           \
  53                 (val) = (u32)(in_be64(&pmd_regs->reg) >> 32);   \
  54         } while (0)
  55 
  56 /*
  57  * Physical counter registers.
  58  * Each physical counter can act as one 32-bit counter or two 16-bit counters.
  59  */
  60 
  61 u32 cbe_read_phys_ctr(u32 cpu, u32 phys_ctr)
  62 {
  63         u32 val_in_latch, val = 0;
  64 
  65         if (phys_ctr < NR_PHYS_CTRS) {
  66                 READ_SHADOW_REG(val_in_latch, counter_value_in_latch);
  67 
  68                 /* Read the latch or the actual counter, whichever is newer. */
  69                 if (val_in_latch & (1 << phys_ctr)) {
  70                         READ_SHADOW_REG(val, pm_ctr[phys_ctr]);
  71                 } else {
  72                         READ_MMIO_UPPER32(val, pm_ctr[phys_ctr]);
  73                 }
  74         }
  75 
  76         return val;
  77 }
  78 EXPORT_SYMBOL_GPL(cbe_read_phys_ctr);
  79 
  80 void cbe_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
  81 {
  82         struct cbe_pmd_shadow_regs *shadow_regs;
  83         u32 pm_ctrl;
  84 
  85         if (phys_ctr < NR_PHYS_CTRS) {
  86                 /* Writing to a counter only writes to a hardware latch.
  87                  * The new value is not propagated to the actual counter
  88                  * until the performance monitor is enabled.
  89                  */
  90                 WRITE_WO_MMIO(pm_ctr[phys_ctr], val);
  91 
  92                 pm_ctrl = cbe_read_pm(cpu, pm_control);
  93                 if (pm_ctrl & CBE_PM_ENABLE_PERF_MON) {
  94                         /* The counters are already active, so we need to
  95                          * rewrite the pm_control register to "re-enable"
  96                          * the PMU.
  97                          */
  98                         cbe_write_pm(cpu, pm_control, pm_ctrl);
  99                 } else {
 100                         shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
 101                         shadow_regs->counter_value_in_latch |= (1 << phys_ctr);
 102                 }
 103         }
 104 }
 105 EXPORT_SYMBOL_GPL(cbe_write_phys_ctr);
 106 
 107 /*
 108  * "Logical" counter registers.
 109  * These will read/write 16-bits or 32-bits depending on the
 110  * current size of the counter. Counters 4 - 7 are always 16-bit.
 111  */
 112 
 113 u32 cbe_read_ctr(u32 cpu, u32 ctr)
 114 {
 115         u32 val;
 116         u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
 117 
 118         val = cbe_read_phys_ctr(cpu, phys_ctr);
 119 
 120         if (cbe_get_ctr_size(cpu, phys_ctr) == 16)
 121                 val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
 122 
 123         return val;
 124 }
 125 EXPORT_SYMBOL_GPL(cbe_read_ctr);
 126 
 127 void cbe_write_ctr(u32 cpu, u32 ctr, u32 val)
 128 {
 129         u32 phys_ctr;
 130         u32 phys_val;
 131 
 132         phys_ctr = ctr & (NR_PHYS_CTRS - 1);
 133 
 134         if (cbe_get_ctr_size(cpu, phys_ctr) == 16) {
 135                 phys_val = cbe_read_phys_ctr(cpu, phys_ctr);
 136 
 137                 if (ctr < NR_PHYS_CTRS)
 138                         val = (val << 16) | (phys_val & 0xffff);
 139                 else
 140                         val = (val & 0xffff) | (phys_val & 0xffff0000);
 141         }
 142 
 143         cbe_write_phys_ctr(cpu, phys_ctr, val);
 144 }
 145 EXPORT_SYMBOL_GPL(cbe_write_ctr);
 146 
 147 /*
 148  * Counter-control registers.
 149  * Each "logical" counter has a corresponding control register.
 150  */
 151 
 152 u32 cbe_read_pm07_control(u32 cpu, u32 ctr)
 153 {
 154         u32 pm07_control = 0;
 155 
 156         if (ctr < NR_CTRS)
 157                 READ_SHADOW_REG(pm07_control, pm07_control[ctr]);
 158 
 159         return pm07_control;
 160 }
 161 EXPORT_SYMBOL_GPL(cbe_read_pm07_control);
 162 
 163 void cbe_write_pm07_control(u32 cpu, u32 ctr, u32 val)
 164 {
 165         if (ctr < NR_CTRS)
 166                 WRITE_WO_MMIO(pm07_control[ctr], val);
 167 }
 168 EXPORT_SYMBOL_GPL(cbe_write_pm07_control);
 169 
 170 /*
 171  * Other PMU control registers. Most of these are write-only.
 172  */
 173 
 174 u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg)
 175 {
 176         u32 val = 0;
 177 
 178         switch (reg) {
 179         case group_control:
 180                 READ_SHADOW_REG(val, group_control);
 181                 break;
 182 
 183         case debug_bus_control:
 184                 READ_SHADOW_REG(val, debug_bus_control);
 185                 break;
 186 
 187         case trace_address:
 188                 READ_MMIO_UPPER32(val, trace_address);
 189                 break;
 190 
 191         case ext_tr_timer:
 192                 READ_SHADOW_REG(val, ext_tr_timer);
 193                 break;
 194 
 195         case pm_status:
 196                 READ_MMIO_UPPER32(val, pm_status);
 197                 break;
 198 
 199         case pm_control:
 200                 READ_SHADOW_REG(val, pm_control);
 201                 break;
 202 
 203         case pm_interval:
 204                 READ_MMIO_UPPER32(val, pm_interval);
 205                 break;
 206 
 207         case pm_start_stop:
 208                 READ_SHADOW_REG(val, pm_start_stop);
 209                 break;
 210         }
 211 
 212         return val;
 213 }
 214 EXPORT_SYMBOL_GPL(cbe_read_pm);
 215 
 216 void cbe_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
 217 {
 218         switch (reg) {
 219         case group_control:
 220                 WRITE_WO_MMIO(group_control, val);
 221                 break;
 222 
 223         case debug_bus_control:
 224                 WRITE_WO_MMIO(debug_bus_control, val);
 225                 break;
 226 
 227         case trace_address:
 228                 WRITE_WO_MMIO(trace_address, val);
 229                 break;
 230 
 231         case ext_tr_timer:
 232                 WRITE_WO_MMIO(ext_tr_timer, val);
 233                 break;
 234 
 235         case pm_status:
 236                 WRITE_WO_MMIO(pm_status, val);
 237                 break;
 238 
 239         case pm_control:
 240                 WRITE_WO_MMIO(pm_control, val);
 241                 break;
 242 
 243         case pm_interval:
 244                 WRITE_WO_MMIO(pm_interval, val);
 245                 break;
 246 
 247         case pm_start_stop:
 248                 WRITE_WO_MMIO(pm_start_stop, val);
 249                 break;
 250         }
 251 }
 252 EXPORT_SYMBOL_GPL(cbe_write_pm);
 253 
 254 /*
 255  * Get/set the size of a physical counter to either 16 or 32 bits.
 256  */
 257 
 258 u32 cbe_get_ctr_size(u32 cpu, u32 phys_ctr)
 259 {
 260         u32 pm_ctrl, size = 0;
 261 
 262         if (phys_ctr < NR_PHYS_CTRS) {
 263                 pm_ctrl = cbe_read_pm(cpu, pm_control);
 264                 size = (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
 265         }
 266 
 267         return size;
 268 }
 269 EXPORT_SYMBOL_GPL(cbe_get_ctr_size);
 270 
 271 void cbe_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
 272 {
 273         u32 pm_ctrl;
 274 
 275         if (phys_ctr < NR_PHYS_CTRS) {
 276                 pm_ctrl = cbe_read_pm(cpu, pm_control);
 277                 switch (ctr_size) {
 278                 case 16:
 279                         pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
 280                         break;
 281 
 282                 case 32:
 283                         pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
 284                         break;
 285                 }
 286                 cbe_write_pm(cpu, pm_control, pm_ctrl);
 287         }
 288 }
 289 EXPORT_SYMBOL_GPL(cbe_set_ctr_size);
 290 
 291 /*
 292  * Enable/disable the entire performance monitoring unit.
 293  * When we enable the PMU, all pending writes to counters get committed.
 294  */
 295 
 296 void cbe_enable_pm(u32 cpu)
 297 {
 298         struct cbe_pmd_shadow_regs *shadow_regs;
 299         u32 pm_ctrl;
 300 
 301         shadow_regs = cbe_get_cpu_pmd_shadow_regs(cpu);
 302         shadow_regs->counter_value_in_latch = 0;
 303 
 304         pm_ctrl = cbe_read_pm(cpu, pm_control) | CBE_PM_ENABLE_PERF_MON;
 305         cbe_write_pm(cpu, pm_control, pm_ctrl);
 306 }
 307 EXPORT_SYMBOL_GPL(cbe_enable_pm);
 308 
 309 void cbe_disable_pm(u32 cpu)
 310 {
 311         u32 pm_ctrl;
 312         pm_ctrl = cbe_read_pm(cpu, pm_control) & ~CBE_PM_ENABLE_PERF_MON;
 313         cbe_write_pm(cpu, pm_control, pm_ctrl);
 314 }
 315 EXPORT_SYMBOL_GPL(cbe_disable_pm);
 316 
 317 /*
 318  * Reading from the trace_buffer.
 319  * The trace buffer is two 64-bit registers. Reading from
 320  * the second half automatically increments the trace_address.
 321  */
 322 
 323 void cbe_read_trace_buffer(u32 cpu, u64 *buf)
 324 {
 325         struct cbe_pmd_regs __iomem *pmd_regs = cbe_get_cpu_pmd_regs(cpu);
 326 
 327         *buf++ = in_be64(&pmd_regs->trace_buffer_0_63);
 328         *buf++ = in_be64(&pmd_regs->trace_buffer_64_127);
 329 }
 330 EXPORT_SYMBOL_GPL(cbe_read_trace_buffer);
 331 
 332 /*
 333  * Enabling/disabling interrupts for the entire performance monitoring unit.
 334  */
 335 
 336 u32 cbe_get_and_clear_pm_interrupts(u32 cpu)
 337 {
 338         /* Reading pm_status clears the interrupt bits. */
 339         return cbe_read_pm(cpu, pm_status);
 340 }
 341 EXPORT_SYMBOL_GPL(cbe_get_and_clear_pm_interrupts);
 342 
 343 void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
 344 {
 345         /* Set which node and thread will handle the next interrupt. */
 346         iic_set_interrupt_routing(cpu, thread, 0);
 347 
 348         /* Enable the interrupt bits in the pm_status register. */
 349         if (mask)
 350                 cbe_write_pm(cpu, pm_status, mask);
 351 }
 352 EXPORT_SYMBOL_GPL(cbe_enable_pm_interrupts);
 353 
 354 void cbe_disable_pm_interrupts(u32 cpu)
 355 {
 356         cbe_get_and_clear_pm_interrupts(cpu);
 357         cbe_write_pm(cpu, pm_status, 0);
 358 }
 359 EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts);
 360 
 361 static irqreturn_t cbe_pm_irq(int irq, void *dev_id)
 362 {
 363         perf_irq(get_irq_regs());
 364         return IRQ_HANDLED;
 365 }
 366 
 367 static int __init cbe_init_pm_irq(void)
 368 {
 369         unsigned int irq;
 370         int rc, node;
 371 
 372         for_each_online_node(node) {
 373                 irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI |
 374                                                (node << IIC_IRQ_NODE_SHIFT));
 375                 if (!irq) {
 376                         printk("ERROR: Unable to allocate irq for node %d\n",
 377                                node);
 378                         return -EINVAL;
 379                 }
 380 
 381                 rc = request_irq(irq, cbe_pm_irq,
 382                                  0, "cbe-pmu-0", NULL);
 383                 if (rc) {
 384                         printk("ERROR: Request for irq on node %d failed\n",
 385                                node);
 386                         return rc;
 387                 }
 388         }
 389 
 390         return 0;
 391 }
 392 machine_arch_initcall(cell, cbe_init_pm_irq);
 393 
 394 void cbe_sync_irq(int node)
 395 {
 396         unsigned int irq;
 397 
 398         irq = irq_find_mapping(NULL,
 399                                IIC_IRQ_IOEX_PMI
 400                                | (node << IIC_IRQ_NODE_SHIFT));
 401 
 402         if (!irq) {
 403                 printk(KERN_WARNING "ERROR, unable to get existing irq %d " \
 404                 "for node %d\n", irq, node);
 405                 return;
 406         }
 407 
 408         synchronize_irq(irq);
 409 }
 410 EXPORT_SYMBOL_GPL(cbe_sync_irq);
 411 

/* [<][>][^][v][top][bottom][index][help] */