static int scu_start(void) { struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; unsigned int temp, i; unsigned long event; int ret = 0; /* * request the SCU counter interrupts that we need */ for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) { ret = request_irq(IRQ_EB11MP_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED, "SCU PMU", NULL); if (ret) { printk(KERN_ERR "oprofile: unable to request IRQ%u for SCU Event Monitor\n", IRQ_EB11MP_PMU_SCU0 + i); goto err_free_scu; } } } /* * clear overflow and enable interrupt for all used counters */ temp = readl(&emc->PMCR); for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) { scu_reset_counter(emc, i); event = counter_config[SCU_COUNTER(i)].event; scu_set_event(emc, i, event); /* clear overflow/interrupt */ temp |= 1 << (i + 16); /* enable interrupt*/ temp |= 1 << (i + 8); } } /* Enable all 8 counters */ temp |= PMCR_E; writel(temp, &emc->PMCR); return 0; err_free_scu: while (i--) free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL); return ret; }
/* * SCU counters' IRQ handler (one IRQ per counter => 2 IRQs per CPU) */ static irqreturn_t scu_em_interrupt(int irq, void *arg) { struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; unsigned int cnt; cnt = irq - IRQ_EB11MP_PMU_SCU0; oprofile_add_sample(get_irq_regs(), SCU_COUNTER(cnt)); scu_reset_counter(emc, cnt); /* Clear overflow flag for this counter */ writel(1 << (cnt + 16), &emc->PMCR); return IRQ_HANDLED; }
static void scu_stop(void) { struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE; unsigned int temp, i; /* Disable counter interrupts */ /* Don't disable all 8 counters (with the E bit) as they may be in use */ temp = readl(&emc->PMCR); for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) temp &= ~(1 << (i + 8)); } writel(temp, &emc->PMCR); /* Free counter interrupts and reset counters */ for (i = 0; i < NUM_SCU_COUNTERS; i++) { if (scu_em_used & (1 << i)) { scu_reset_counter(emc, i); free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL); } } }