2 * Copyright (c) 2015 Imre Vadász <imre@vdsz.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
28 * Device driver for Intel's On Die power usage estimation via MSR.
29 * Supported by Sandy Bridge and later CPUs, and also by Atom CPUs
30 * of the Silvermont and later architectures.
33 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/module.h>
38 #include <sys/cpu_topology.h>
39 #include <sys/kernel.h>
40 #include <sys/sensors.h>
41 #include <sys/bitops.h>
43 #include <machine/specialreg.h>
44 #include <machine/cpufunc.h>
45 #include <machine/cputypes.h>
46 #include <machine/md_var.h>
50 #define MSR_RAPL_POWER_UNIT_POWER __BITS64(0, 3)
51 #define MSR_RAPL_POWER_UNIT_ENERGY __BITS64(8, 12)
52 #define MSR_RAPL_POWER_UNIT_TIME __BITS64(16, 19)
54 struct corepower_sensor {
57 struct ksensor sensor;
60 struct corepower_softc {
63 uint32_t sc_watt_divisor;
64 uint32_t sc_joule_divisor;
65 uint32_t sc_second_divisor;
69 struct corepower_sensor sc_pkg_sens;
70 struct corepower_sensor sc_dram_sens;
71 struct corepower_sensor sc_pp0_sens;
72 struct corepower_sensor sc_pp1_sens;
74 struct ksensordev sc_sensordev;
75 struct sensor_task *sc_senstask;
81 static void corepower_identify(driver_t *driver, device_t parent);
82 static int corepower_probe(device_t dev);
83 static int corepower_attach(device_t dev);
84 static int corepower_detach(device_t dev);
85 static uint32_t corepower_energy_to_uwatts(struct corepower_softc *sc,
86 uint32_t units, uint32_t secs);
87 static void corepower_refresh(void *arg);
88 static void corepower_sens_init(struct corepower_sensor *sens,
89 char *desc, u_int msr, int cpu);
90 static void corepower_sens_update(struct corepower_softc *sc,
91 struct corepower_sensor *sens);
93 static device_method_t corepower_methods[] = {
94 /* Device interface */
95 DEVMETHOD(device_identify, corepower_identify),
96 DEVMETHOD(device_probe, corepower_probe),
97 DEVMETHOD(device_attach, corepower_attach),
98 DEVMETHOD(device_detach, corepower_detach),
103 static driver_t corepower_driver = {
106 sizeof(struct corepower_softc),
109 static devclass_t corepower_devclass;
110 DRIVER_MODULE(corepower, cpu, corepower_driver, corepower_devclass, NULL, NULL);
111 MODULE_VERSION(corepower, 1);
114 corepower_identify(driver_t *driver, device_t parent)
117 const struct cpu_node *node;
120 /* Make sure we're not being doubly invoked. */
121 if (device_find_child(parent, "corepower", -1) != NULL)
124 /* Check that the vendor is Intel. */
125 if (cpu_vendor_id != CPU_VENDOR_INTEL)
128 /* We only want one child per CPU package */
129 cpu = device_get_unit(parent);
130 node = get_cpu_node_by_cpuid(cpu);
131 while (node != NULL) {
132 if (node->type == PACKAGE_LEVEL) {
133 if (node->child_no == 0)
137 node = node->parent_node;
142 master_cpu = BSRCPUMASK(node->members);
143 if (cpu != master_cpu)
146 child = device_add_child(parent, "corepower", -1);
148 device_printf(parent, "add corepower child failed\n");
152 corepower_probe(device_t dev)
154 int cpu_family, cpu_model;
156 if (resource_disabled("corepower", 0))
159 cpu_model = CPUID_TO_MODEL(cpu_id);
160 cpu_family = CPUID_TO_FAMILY(cpu_id);
162 if (cpu_family == 0x06) {
173 /* Haswell, Broadwell, Skylake */
193 device_set_desc(dev, "CPU On-Die Power Usage Estimation");
195 return (BUS_PROBE_GENERIC);
199 corepower_attach(device_t dev)
201 struct corepower_softc *sc = device_get_softc(dev);
203 uint32_t power_units;
204 uint32_t energy_units;
206 int cpu_family, cpu_model;
210 sc->sc_have_sens = 0;
212 cpu_family = CPUID_TO_FAMILY(cpu_id);
213 cpu_model = CPUID_TO_MODEL(cpu_id);
215 /* XXX Check CPU version */
216 if (cpu_family == 0x06) {
221 sc->sc_have_sens = 0xd;
224 case 0x2d: /* Only Xeon branded, Core i version should probably be 0x5 */
229 sc->sc_have_sens = 0x7;
231 /* Haswell, Broadwell, Skylake */
239 /* Check if Core or Xeon (Xeon CPUs might be 0x7) */
240 sc->sc_have_sens = 0xf;
248 sc->sc_have_sens = 0x5;
255 val = rdmsr(MSR_RAPL_POWER_UNIT);
257 power_units = __SHIFTOUT(val, MSR_RAPL_POWER_UNIT_POWER);
258 energy_units = __SHIFTOUT(val, MSR_RAPL_POWER_UNIT_ENERGY);
259 time_units = __SHIFTOUT(val, MSR_RAPL_POWER_UNIT_TIME);
261 sc->sc_watt_divisor = (1 << power_units);
262 sc->sc_joule_divisor = (1 << energy_units);
263 sc->sc_second_divisor = (1 << time_units);
266 * Add hw.sensors.cpu_nodeN MIB.
268 cpu = device_get_unit(device_get_parent(dev));
269 ksnprintf(sc->sc_sensordev.xname, sizeof(sc->sc_sensordev.xname),
270 "cpu_node%d", get_chip_ID(cpu));
271 if (sc->sc_have_sens & 1) {
272 corepower_sens_init(&sc->sc_pkg_sens, "Package Power",
273 MSR_PKG_ENERGY_STATUS, cpu);
274 sensor_attach(&sc->sc_sensordev, &sc->sc_pkg_sens.sensor);
276 if (sc->sc_have_sens & 2) {
277 corepower_sens_init(&sc->sc_dram_sens, "DRAM Power",
278 MSR_DRAM_ENERGY_STATUS, cpu);
279 sensor_attach(&sc->sc_sensordev, &sc->sc_dram_sens.sensor);
281 if (sc->sc_have_sens & 4) {
282 corepower_sens_init(&sc->sc_pp0_sens, "Cores Power",
283 MSR_PP0_ENERGY_STATUS, cpu);
284 sensor_attach(&sc->sc_sensordev, &sc->sc_pp0_sens.sensor);
286 if (sc->sc_have_sens & 8) {
287 corepower_sens_init(&sc->sc_pp1_sens, "Graphics Power",
288 MSR_PP1_ENERGY_STATUS, cpu);
289 sensor_attach(&sc->sc_sensordev, &sc->sc_pp1_sens.sensor);
292 sc->sc_senstask = sensor_task_register2(sc, corepower_refresh, 1, cpu);
294 sensordev_install(&sc->sc_sensordev);
300 corepower_detach(device_t dev)
302 struct corepower_softc *sc = device_get_softc(dev);
304 sensordev_deinstall(&sc->sc_sensordev);
305 sensor_task_unregister2(sc->sc_senstask);
311 corepower_energy_to_uwatts(struct corepower_softc *sc, uint32_t units,
316 val = ((uint64_t)units) * 1000ULL * 1000ULL;
317 val /= sc->sc_joule_divisor;
323 corepower_refresh(void *arg)
325 struct corepower_softc *sc = (struct corepower_softc *)arg;
327 if (sc->sc_have_sens & 1)
328 corepower_sens_update(sc, &sc->sc_pkg_sens);
329 if (sc->sc_have_sens & 2)
330 corepower_sens_update(sc, &sc->sc_dram_sens);
331 if (sc->sc_have_sens & 4)
332 corepower_sens_update(sc, &sc->sc_pp0_sens);
333 if (sc->sc_have_sens & 8)
334 corepower_sens_update(sc, &sc->sc_pp1_sens);
338 corepower_sens_init(struct corepower_sensor *sens, char *desc, u_int msr,
341 ksnprintf(sens->sensor.desc, sizeof(sens->sensor.desc), "node%d %s",
342 get_chip_ID(cpu), desc);
343 sens->sensor.type = SENSOR_WATTS;
345 sens->energy = rdmsr(sens->msr) & 0xffffffffU;
349 corepower_sens_update(struct corepower_softc *sc,
350 struct corepower_sensor *sens)
354 a = rdmsr(sens->msr) & 0xffffffffU;
355 if (sens->energy > a) {
356 res = (0x100000000ULL - sens->energy) + a;
358 res = a - sens->energy;
361 sens->sensor.value = corepower_energy_to_uwatts(sc, res, 1);