Page MenuHomeFreeBSD

D55603.diff
No OneTemporary

D55603.diff

diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -62,6 +62,7 @@
dev/agp/agp_amd64.c optional agp
dev/agp/agp_i810.c optional agp
dev/agp/agp_via.c optional agp
+dev/amdrapl/amdrapl.c optional amdrapl
dev/amdsmu/amdsmu.c optional amdsmu pci
dev/amdsbwd/amdsbwd.c optional amdsbwd
dev/amdsmn/amdsmn.c optional amdsmn | amdtemp
diff --git a/sys/dev/amdrapl/amdrapl.c b/sys/dev/amdrapl/amdrapl.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/amdrapl/amdrapl.c
@@ -0,0 +1,247 @@
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/callout.h>
+#include <sys/cpu.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/smp.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+
+#include <machine/cputypes.h>
+#include <machine/specialreg.h>
+
+#include <x86/x86_var.h>
+
+#define AMD_RAPL_DRIVER_NAME "amd_rapl"
+
+#define MSR_RAPL_PWRUNIT 0xC0010299
+#define MSR_RAPL_CORE_ENERGY_STATUS 0xC001029A
+#define MSR_RAPL_PACKAGE_ENERGY_STATUS 0xC001029B
+#define AMD_RAPL_SAMPLE_UNIT 10
+
+struct amd_rapl_value {
+ uint64_t prev;
+ volatile uint64_t diff;
+};
+
+struct amd_rapl_softc {
+ struct callout sampling_timer;
+ struct mtx mtx;
+ uint32_t energy_unit;
+ device_t dev;
+ uint32_t cpus_per_domain;
+ struct amd_rapl_value *core_value;
+ struct amd_rapl_value *package_value;
+};
+
+static uint64_t
+amd_rapl_count_watt(struct amd_rapl_softc *sc, struct amd_rapl_value *val)
+{
+ return ((val->diff) * 100 * 1000 / (1UL << sc->energy_unit));
+}
+
+static void
+amd_rapl_update_delta(struct amd_rapl_value *val, uint64_t cur)
+{
+ if (cur > val->prev)
+ val->diff = cur - val->prev;
+ else
+ val->diff = UINT32_MAX - val->prev + cur;
+ val->prev = cur;
+}
+
+static void
+amd_rapl_read_core_energy(void *arg)
+{
+ struct amd_rapl_softc *sc = arg;
+ uint64_t cur;
+
+ rdmsr_safe(MSR_RAPL_CORE_ENERGY_STATUS, &cur);
+ amd_rapl_update_delta(&sc->core_value[curcpu], cur);
+}
+
+static void
+amd_rapl_read_package_energy(void *arg)
+{
+ struct amd_rapl_softc *sc = arg;
+ uint64_t cur;
+
+ rdmsr_safe(MSR_RAPL_PACKAGE_ENERGY_STATUS, &cur);
+ amd_rapl_update_delta(&sc->package_value[curcpu / sc->cpus_per_domain],
+ cur);
+}
+
+static void
+amd_rapl_sample(void *arg)
+{
+ struct amd_rapl_softc *sc = arg;
+ int i;
+ cpuset_t package_cpus;
+
+ mtx_unlock(&sc->mtx);
+ smp_rendezvous_cpus(all_cpus, smp_no_rendezvous_barrier,
+ amd_rapl_read_core_energy, smp_no_rendezvous_barrier, sc);
+ for (i = 0; i < vm_ndomains; i++)
+ CPU_SETOF(i * sc->cpus_per_domain, &package_cpus);
+ smp_rendezvous_cpus(package_cpus, smp_no_rendezvous_barrier,
+ amd_rapl_read_package_energy, smp_no_rendezvous_barrier, sc);
+ callout_schedule_sbt(&sc->sampling_timer,
+ SBT_1MS * AMD_RAPL_SAMPLE_UNIT, SBT_1MS, 0);
+}
+static int
+sysctl_amd_rapl_display_package(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf sbs, *sb;
+ struct amd_rapl_softc *sc = arg1;
+ int err, i;
+
+ sb = sbuf_new_for_sysctl(&sbs, NULL, 0, req);
+ sbuf_printf(sb, "%lu", amd_rapl_count_watt(sc, &sc->package_value[0]));
+ for (i = 1; i < vm_ndomains; i++)
+ sbuf_printf(sb, "%lu",
+ amd_rapl_count_watt(sc, &sc->package_value[i]));
+ err = sbuf_finish(sb);
+ sbuf_delete(sb);
+ return (err);
+}
+
+static int
+sysctl_amd_rapl_display_cores(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf sbs, *sb;
+ struct amd_rapl_softc *sc = arg1;
+ int err, i;
+
+ sb = sbuf_new_for_sysctl(&sbs, NULL, 0, req);
+ sbuf_printf(sb, "%lu", amd_rapl_count_watt(sc, &sc->core_value[0]));
+ for (i = 1; i < mp_ncpus; ++i)
+ sbuf_printf(sb, ",%lu",
+ amd_rapl_count_watt(sc, &sc->core_value[i]));
+ err = sbuf_finish(sb);
+ sbuf_delete(sb);
+ return (err);
+}
+
+static void
+amd_rapl_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+
+ /* Make sure we're not being doubly invoked. */
+ if (device_find_child(parent, AMD_RAPL_DRIVER_NAME, DEVICE_UNIT_ANY) !=
+ NULL)
+ return;
+ child = device_add_child(parent, AMD_RAPL_DRIVER_NAME, DEVICE_UNIT_ANY);
+ if (child == NULL)
+ device_printf(parent,
+ "add " AMD_RAPL_DRIVER_NAME "child failed\n");
+}
+
+static int
+amd_rapl_probe(device_t dev)
+{
+ if (cpu_vendor_id != CPU_VENDOR_AMD)
+ return (ENXIO);
+ if (!(amd_pminfo & AMDPM_RAPL))
+ return (ENXIO);
+ if (resource_disabled(AMD_RAPL_DRIVER_NAME, 0))
+ return (ENXIO);
+ /*
+ * Only create a device for all cpu core.
+ */
+ if (device_get_unit(dev) != 0)
+ return (ENXIO);
+ device_set_desc(dev, "AMD RAPL");
+ return (0);
+
+}
+static int
+amd_rapl_attach(device_t dev)
+{
+ struct amd_rapl_softc *sc = device_get_softc(dev);
+ uint64_t value;
+
+ sc->dev = dev;
+ x86_msr_op(MSR_RAPL_PWRUNIT,
+ MSR_OP_RENDEZVOUS_ONE | MSR_OP_READ |
+ MSR_OP_CPUID(cpu_get_pcpu(dev)->pc_cpuid),
+ 0, &value);
+ sc->energy_unit = (value >> 8) & 0x1f;
+ sc->cpus_per_domain = mp_ncpus / vm_ndomains;
+ sc->core_value = malloc(sizeof(struct amd_rapl_value) * mp_ncpus,
+ M_TEMP, M_WAITOK);
+ sc->package_value = malloc(sizeof(struct amd_rapl_value) * vm_ndomains,
+ M_TEMP, M_WAITOK);
+ mtx_init(&sc->mtx, AMD_RAPL_DRIVER_NAME, NULL, MTX_DEF | MTX_RECURSE);
+ callout_init_mtx(&sc->sampling_timer, &sc->mtx, CALLOUT_RETURNUNLOCKED);
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "package_mwatt", CTLTYPE_STRING | CTLFLAG_RDTUN | CTLFLAG_MPSAFE,
+ sc, 0, sysctl_amd_rapl_display_package, "A", "");
+ SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "cores_mwatt", CTLTYPE_STRING | CTLFLAG_RDTUN | CTLFLAG_MPSAFE, sc,
+ 0, sysctl_amd_rapl_display_cores, "A", "");
+ callout_reset_sbt(&sc->sampling_timer, SBT_1MS * AMD_RAPL_SAMPLE_UNIT,
+ SBT_1MS, amd_rapl_sample, sc, 0);
+ return (0);
+}
+
+static int
+amd_rapl_detach(device_t dev)
+{
+ struct amd_rapl_softc *sc = device_get_softc(dev);
+
+ if (callout_active(&sc->sampling_timer))
+ callout_drain(&sc->sampling_timer);
+ mtx_destroy(&sc->mtx);
+ free(sc->core_value, M_TEMP);
+ free(sc->package_value, M_TEMP);
+ return (0);
+}
+
+static int
+amd_rapl_suspend(device_t dev)
+{
+ struct amd_rapl_softc *sc = device_get_softc(dev);
+
+ if (callout_active(&sc->sampling_timer))
+ callout_drain(&sc->sampling_timer);
+ return (0);
+}
+
+static int
+amd_rapl_resume(device_t dev)
+{
+ struct amd_rapl_softc *sc = device_get_softc(dev);
+
+ if (callout_deactivate(&sc->sampling_timer)) {
+ callout_reset_sbt(&sc->sampling_timer,
+ SBT_1MS * AMD_RAPL_SAMPLE_UNIT, SBT_1MS, amd_rapl_sample,
+ sc, 0);
+ }
+ return (0);
+}
+
+static device_method_t amd_rapl_methods[] = {
+ DEVMETHOD(device_identify, amd_rapl_identify),
+ DEVMETHOD(device_probe, amd_rapl_probe),
+ DEVMETHOD(device_attach, amd_rapl_attach),
+ DEVMETHOD(device_detach, amd_rapl_detach),
+ DEVMETHOD(device_suspend, amd_rapl_suspend),
+ DEVMETHOD(device_resume, amd_rapl_resume),
+};
+
+static driver_t amd_rapl_driver = {
+ AMD_RAPL_DRIVER_NAME,
+ amd_rapl_methods,
+ sizeof(struct amd_rapl_softc),
+};
+
+DRIVER_MODULE(amd_rapl, cpu, amd_rapl_driver, 0, 0);
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -34,6 +34,7 @@
alq \
${_amd_ecc_inject} \
${_amdgpio} \
+ ${_amdrapl} \
${_amdsmu} \
${_amdsbwd} \
${_amdsmn} \
@@ -789,6 +790,7 @@
_aesni= aesni
.endif
_amd_ecc_inject=amd_ecc_inject
+_amdrapl= amdrapl
_amdsmu= amdsmu
_amdsbwd= amdsbwd
_amdsmn= amdsmn
diff --git a/sys/modules/amdrapl/Makefile b/sys/modules/amdrapl/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/amdrapl/Makefile
@@ -0,0 +1,8 @@
+.PATH: ${SRCTOP}/sys/dev/amdrapl
+
+KMOD= amdrapl
+SRCS= amdrapl.c bus_if.h device_if.h
+
+EXPORT_SYMS= YES
+
+.include <bsd.kmod.mk>
diff --git a/sys/x86/conf/NOTES b/sys/x86/conf/NOTES
--- a/sys/x86/conf/NOTES
+++ b/sys/x86/conf/NOTES
@@ -622,6 +622,9 @@
#
device superio
+# Running Average Power Limit
+device amdrapl
+
#####################################################################
# More undocumented options for linting.
diff --git a/sys/x86/include/specialreg.h b/sys/x86/include/specialreg.h
--- a/sys/x86/include/specialreg.h
+++ b/sys/x86/include/specialreg.h
@@ -419,6 +419,7 @@
#define AMDPM_TSC_INVARIANT 0x00000100
#define AMDPM_CPB 0x00000200
#define AMDPM_PWR_REPORT 0x00001000
+#define AMDPM_RAPL 0x00004000
/*
* AMD extended function 8000_0008h ebx info (amd_extended_feature_extensions)

File Metadata

Mime Type
text/plain
Expires
Thu, Mar 5, 1:35 PM (10 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29286775
Default Alt Text
D55603.diff (8 KB)

Event Timeline