Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  arch/powerpc/kernel/pmc.c
0004  *
0005  *  Copyright (C) 2004 David Gibson, IBM Corporation.
0006  *  Includes code formerly from arch/ppc/kernel/perfmon.c:
0007  *    Author: Andy Fleming
0008  *    Copyright (c) 2004 Freescale Semiconductor, Inc
0009  */
0010 
0011 #include <linux/errno.h>
0012 #include <linux/bug.h>
0013 #include <linux/spinlock.h>
0014 #include <linux/export.h>
0015 
0016 #include <asm/processor.h>
0017 #include <asm/cputable.h>
0018 #include <asm/pmc.h>
0019 
0020 #ifndef MMCR0_PMAO
0021 #define MMCR0_PMAO  0
0022 #endif
0023 
0024 static void dummy_perf(struct pt_regs *regs)
0025 {
0026 #if defined(CONFIG_FSL_EMB_PERFMON)
0027     mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
0028 #elif defined(CONFIG_PPC64) || defined(CONFIG_PPC_BOOK3S_32)
0029     if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
0030         mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~(MMCR0_PMXE|MMCR0_PMAO));
0031 #else
0032     mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMXE);
0033 #endif
0034 }
0035 
0036 
0037 static DEFINE_RAW_SPINLOCK(pmc_owner_lock);
0038 static void *pmc_owner_caller; /* mostly for debugging */
0039 perf_irq_t perf_irq = dummy_perf;
0040 
0041 int reserve_pmc_hardware(perf_irq_t new_perf_irq)
0042 {
0043     int err = 0;
0044 
0045     raw_spin_lock(&pmc_owner_lock);
0046 
0047     if (pmc_owner_caller) {
0048         printk(KERN_WARNING "reserve_pmc_hardware: "
0049                "PMC hardware busy (reserved by caller %p)\n",
0050                pmc_owner_caller);
0051         err = -EBUSY;
0052         goto out;
0053     }
0054 
0055     pmc_owner_caller = __builtin_return_address(0);
0056     perf_irq = new_perf_irq ? new_perf_irq : dummy_perf;
0057 
0058  out:
0059     raw_spin_unlock(&pmc_owner_lock);
0060     return err;
0061 }
0062 EXPORT_SYMBOL_GPL(reserve_pmc_hardware);
0063 
0064 void release_pmc_hardware(void)
0065 {
0066     raw_spin_lock(&pmc_owner_lock);
0067 
0068     WARN_ON(! pmc_owner_caller);
0069 
0070     pmc_owner_caller = NULL;
0071     perf_irq = dummy_perf;
0072 
0073     raw_spin_unlock(&pmc_owner_lock);
0074 }
0075 EXPORT_SYMBOL_GPL(release_pmc_hardware);
0076 
0077 #ifdef CONFIG_PPC64
0078 void power4_enable_pmcs(void)
0079 {
0080     unsigned long hid0;
0081 
0082     hid0 = mfspr(SPRN_HID0);
0083     hid0 |= 1UL << (63 - 20);
0084 
0085     /* POWER4 requires the following sequence */
0086     asm volatile(
0087         "sync\n"
0088         "mtspr     %1, %0\n"
0089         "mfspr     %0, %1\n"
0090         "mfspr     %0, %1\n"
0091         "mfspr     %0, %1\n"
0092         "mfspr     %0, %1\n"
0093         "mfspr     %0, %1\n"
0094         "mfspr     %0, %1\n"
0095         "isync" : "=&r" (hid0) : "i" (SPRN_HID0), "0" (hid0):
0096         "memory");
0097 }
0098 #endif /* CONFIG_PPC64 */