1 /*- 2 * Copyright (c) 2003-2008 Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "opt_hwpmc_hooks.h" 35 36 #include <sys/types.h> 37 #include <sys/pmc.h> 38 #include <sys/pmckern.h> 39 #include <sys/smp.h> 40 #include <sys/sysctl.h> 41 42 #ifdef HWPMC_HOOKS 43 FEATURE(hwpmc_hooks, "Kernel support for HW PMC"); 44 #define PMC_KERNEL_VERSION PMC_VERSION 45 #else 46 #define PMC_KERNEL_VERSION 0 47 #endif 48 49 const int pmc_kernel_version = PMC_KERNEL_VERSION; 50 51 /* Hook variable. */ 52 int (*pmc_hook)(struct thread *td, int function, void *arg) = NULL; 53 54 /* Interrupt handler */ 55 int (*pmc_intr)(int cpu, struct trapframe *tf) = NULL; 56 57 /* Bitmask of CPUs requiring servicing at hardclock time */ 58 volatile cpumask_t pmc_cpumask; 59 60 /* 61 * A global count of SS mode PMCs. When non-zero, this means that 62 * we have processes that are sampling the system as a whole. 63 */ 64 volatile int pmc_ss_count; 65 66 /* 67 * Since PMC(4) may not be loaded in the current kernel, the 68 * convention followed is that a non-NULL value of 'pmc_hook' implies 69 * the presence of this kernel module. 70 * 71 * This requires us to protect 'pmc_hook' with a 72 * shared (sx) lock -- thus making the process of calling into PMC(4) 73 * somewhat more expensive than a simple 'if' check and indirect call. 74 */ 75 struct sx pmc_sx; 76 77 static void 78 pmc_init_sx(void) 79 { 80 sx_init_flags(&pmc_sx, "pmc-sx", SX_NOWITNESS); 81 } 82 83 SYSINIT(pmcsx, SI_SUB_LOCK, SI_ORDER_MIDDLE, pmc_init_sx, NULL); 84 85 /* 86 * Helper functions. 87 */ 88 89 /* 90 * A note on the CPU numbering scheme used by the hwpmc(4) driver. 91 * 92 * CPUs are denoted using numbers in the range 0..[pmc_cpu_max()-1]. 93 * CPUs could be numbered "sparsely" in this range; the predicate 94 * `pmc_cpu_is_present()' is used to test whether a given CPU is 95 * physically present. 96 * 97 * Further, a CPU that is physically present may be administratively 98 * disabled or otherwise unavailable for use by hwpmc(4). The 99 * `pmc_cpu_is_active()' predicate tests for CPU usability. An 100 * "active" CPU participates in thread scheduling and can field 101 * interrupts raised by PMC hardware. 102 * 103 * On systems with hyperthreaded CPUs, multiple logical CPUs may share 104 * PMC hardware resources. For such processors one logical CPU is 105 * denoted as the primary owner of the in-CPU PMC resources. The 106 * pmc_cpu_is_primary() predicate is used to distinguish this primary 107 * CPU from the others. 108 */ 109 110 int 111 pmc_cpu_is_active(int cpu) 112 { 113 #ifdef SMP 114 return (pmc_cpu_is_present(cpu) && 115 (hlt_cpus_mask & (1 << cpu)) == 0); 116 #else 117 return (1); 118 #endif 119 } 120 121 /* Deprecated. */ 122 int 123 pmc_cpu_is_disabled(int cpu) 124 { 125 return (!pmc_cpu_is_active(cpu)); 126 } 127 128 int 129 pmc_cpu_is_present(int cpu) 130 { 131 #ifdef SMP 132 return (!CPU_ABSENT(cpu)); 133 #else 134 return (1); 135 #endif 136 } 137 138 int 139 pmc_cpu_is_primary(int cpu) 140 { 141 #ifdef SMP 142 return ((logical_cpus_mask & (1 << cpu)) == 0); 143 #else 144 return (1); 145 #endif 146 } 147 148 149 /* 150 * Return the maximum CPU number supported by the system. The return 151 * value is used for scaling internal data structures and for runtime 152 * checks. 153 */ 154 unsigned int 155 pmc_cpu_max(void) 156 { 157 #ifdef SMP 158 return (mp_maxid+1); 159 #else 160 return (1); 161 #endif 162 } 163 164 #ifdef INVARIANTS 165 166 /* 167 * Return the count of CPUs in the `active' state in the system. 168 */ 169 int 170 pmc_cpu_max_active(void) 171 { 172 #ifdef SMP 173 /* 174 * When support for CPU hot-plugging is added to the kernel, 175 * this function would change to return the current number 176 * of "active" CPUs. 177 */ 178 return (mp_ncpus); 179 #else 180 return (1); 181 #endif 182 } 183 184 #endif 185