Page MenuHomeFreeBSD

D44456.id177533.diff
No OneTemporary

D44456.id177533.diff

diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -213,6 +213,7 @@
compile-with "${CP} $S/contrib/dev/ice/ice-1.3.41.0.pkg ice_ddp.fw" \
no-obj no-implicit-rule \
clean "ice_ddp.fw"
+dev/intelhfi/intelhfi.c optional intelhfi
dev/ioat/ioat.c optional ioat pci
dev/ioat/ioat_test.c optional ioat pci
dev/ixl/if_ixl.c optional ixl pci \
diff --git a/sys/conf/options.amd64 b/sys/conf/options.amd64
--- a/sys/conf/options.amd64
+++ b/sys/conf/options.amd64
@@ -40,6 +40,9 @@
# iWARP client interface support in ixl
IXL_IW opt_ixl.h
+# Intel(R) Hardware Feedback Interface driver
+DEV_INTELHFI opt_intelhfi.h
+
# -------------------------------
# EOF
# -------------------------------
diff --git a/sys/dev/intelhfi/intelhfi.c b/sys/dev/intelhfi/intelhfi.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/intelhfi/intelhfi.c
@@ -0,0 +1,789 @@
+/*
+ * Copyright (c) 2024 Koine Yuusuke
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/cdefs.h>
+#include "opt_global.h"
+#include "opt_intelhfi.h"
+
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+#include <sys/sysctl.h>
+#include <sys/sbuf.h>
+
+#ifdef HMP
+#include <sys/hmp.h>
+#endif
+
+#include <machine/specialreg.h>
+#include <machine/cputypes.h>
+#include <machine/md_var.h>
+#include <machine/bus.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+
+#include <x86/intr_machdep.h>
+#include <x86/apicvar.h>
+
+#define INTELHFI_NAME "intelhfi"
+
+/* Check kernel build option with SMP */
+#ifndef SMP
+#error "intelhfi requires the SMP option in the kernel configuraton."
+#endif
+
+#define ROUNDUP8(n) (((n)+7)&(~7))
+
+#define CPUID_LEAF6_ECX_CLASSES(c) ((uint8_t)((((uint64_t)(c)&CPUID_PERF_TD_CLASSES)>>8)&0x0f))
+#define CPUID_LEAF6_EDX_TBLPAGES(c) (((c)&CPUID_TD_TBLPAGES)>>8)
+
+#ifdef HMP
+ #if HMP_CAPACITY_SCALE == 1024
+ #define INTELHFI_HMP_SCORE_FROM(x) ((uint32_t)(x) << 2)
+ #define INTELHFI_HMP_CAPACITY_FROM(x) ((uint32_t)(x) << 2)
+ #else
+ #define INTELHFI_HMP_SCORE_FROM(x) HMP_CAPACITY_NORMAL_FROM_255((x))
+ #define INTELHFI_HMP_CAPACITY_FROM(x) HMP_CAPACITY_NORMAL_FROM_255((x))
+ #endif
+#endif
+
+/* Hardware feedback table - global header flag */
+#define INTELHFI_GH_FLAG_REPORT (1 << 0)
+#define INTELHFI_GH_FLAG_FORCEIDLE (1 << 1)
+
+/*
+ * Structure defines
+ */
+struct intelhfi_instance {
+ uint8_t status;
+
+ struct {
+ uint32_t hfi :1;
+ uint32_t thdirector :1;
+ uint32_t pmaped :1;
+ uint32_t reserved :30;
+ } flags;
+
+ uint32_t hdrsize;
+ uint32_t entrysize;
+ uint32_t allocsize;
+ uint32_t tblsize;
+
+ int32_t cpugroups;
+
+ uint8_t capabilities;
+ uint8_t classes;
+
+ union {
+ void *ptr;
+ uint64_t *timestamp;
+ } hwtable;
+
+ union {
+ void *ptr;
+ uint64_t *timestamp;
+ } cache;
+
+ struct mtx intr_lock;
+
+ struct {
+ struct sysctl_ctx_list ctx;
+ struct sysctl_oid *oid;
+ } sysctl;
+};
+
+#define INTELHFI_STATUS_LOADED (1 << 0) /* status bit0: intelhfi loaded */
+#define INTELHFI_STATUS_USEHMP (1 << 1) /* status bit1: HMP use flag */
+
+static struct intelhfi_instance ihfi_inst;
+
+/*
+ * Prototype defines
+ */
+static void intelhfi_get_hwtable(struct intelhfi_instance *inst);
+static void intelhfi_interrupt(int cpu, void *value);
+static int intelhfi_device_check(void);
+static int intelhfi_device_init(void);
+static int intelhfi_device_remove(void);
+static int intelhfi_modevent(module_t mod, int type, void *data);
+static int intelhfi_sysctl_printtable(SYSCTL_HANDLER_ARGS);
+static int intelhfi_sysctl_dumptable(SYSCTL_HANDLER_ARGS);
+static int intelhfi_regist_sysctl(void);
+static void intelhfi_remove_sysctl(void);
+
+#if !defined(HMP) && defined(DEV_INTELHFI)
+static void intelhfi_sysinit(void *arg __unused);
+#endif /* INTELHFI */
+
+#ifdef HMP
+static int intelhfi_hmp_capacity_provider_probe(void);
+static void intelhfi_hmp_capacity_read_highperf(void *arg);
+static int intelhfi_hmp_capacity_provider_init(void);
+static void intelhfi_hmp_score_initial_flag_set(void);
+static void intelhfi_hmp_score_set(struct intelhfi_instance *inst);
+static int intelhfi_hmp_score_provider_probe(void);
+static int intelhfi_hmp_score_provider_init(void);
+#endif /* HMP */
+
+extern struct cpu_group *cpu_top; /* CPU topology */
+
+#ifdef HMP
+DPCPU_DECLARE(struct hmp_pcpu, hmp_pcpu);
+#endif /* HMP */
+
+static MALLOC_DEFINE(M_INTELHFI, INTELHFI_NAME, "Buffers for intelhfi driver");
+
+/*
+ * HMP capacity provider
+ * (Available only if HMP options are define in kernel configuration.)
+ */
+#ifdef HMP
+static int
+intelhfi_hmp_capacity_provider_probe(void)
+{
+ u_int regs[4];
+
+ /* Check Intel CPU */
+ if (cpu_high < 6 || cpu_vendor_id != CPU_VENDOR_INTEL)
+ return (-1);
+
+ /* Get CPUID Leaf 6 */
+ do_cpuid(0x06, regs);
+
+ /* Check Intel Hardware-Controlled Performance States (HWP) */
+ if(!(regs[0] & CPUTPM1_HWP))
+ return (-2);
+
+ return (0);
+}
+
+static void
+intelhfi_hmp_capacity_read_highperf(void *arg)
+{
+ uint8_t *perf;
+ uint64_t msrval;
+
+ msrval = rdmsr(MSR_IA32_HWP_CAPABILITIES);
+
+ perf = (uint8_t *)arg + PCPU_GET(cpuid);
+ *perf = (uint8_t)IA32_HWP_CAPABILITIES_HIGHEST_PERFORMANCE(msrval);
+}
+
+static int
+intelhfi_hmp_capacity_provider_init(void)
+{
+ struct hmp_pcpu *hp;
+ uint64_t msrval;
+ uint8_t *highperf;
+ int cpu;
+ int ret = 0;
+
+ /* Check & Temporary enable Intel Speed Shift msr */
+ rdmsr_safe(MSR_IA32_PM_ENABLE, &msrval);
+ if (!(msrval & IA32_PM_ENABLE_HWP_ENABLE)) {
+ if (wrmsr_safe(MSR_IA32_PM_ENABLE, (msrval | IA32_PM_ENABLE_HWP_ENABLE)))
+ return (-1);
+ }
+
+ /* Alloc temporary area for CPU core high perf. value */
+ highperf = malloc((sizeof(uint8_t) * mp_ncpus), M_INTELHFI, M_NOWAIT | M_ZERO);
+ if (highperf == NULL) {
+ ret = -2;
+ goto capinit_err;
+ }
+
+ /* Read CPU each core high perf. value from IA32_HWP_CAPABILITIES msr */
+ smp_rendezvous(NULL, intelhfi_hmp_capacity_read_highperf, NULL, highperf);
+
+ /* Set CPU core capacity for HMP */
+ CPU_FOREACH(cpu) {
+ hp = DPCPU_ID_PTR(cpu, hmp_pcpu);
+ hp->capacity = INTELHFI_HMP_CAPACITY_FROM(*(highperf+cpu));
+ }
+
+ free(highperf, M_INTELHFI);
+
+ /* Set intelhfi use HMP flag */
+ ihfi_inst.status |= INTELHFI_STATUS_USEHMP;
+
+capinit_err:
+ /* Undo Intel Speed Shift control msr for hwpstate_intel driver */
+ if (!(msrval & IA32_PM_ENABLE_HWP_ENABLE)) {
+ if (wrmsr_safe(MSR_IA32_PM_ENABLE, msrval))
+ ret = -3;
+ }
+
+ return ret;
+}
+
+static struct hmp_capacity_provider intelhfi_hmp_capacity_provider = {
+ .name = INTELHFI_NAME,
+ .priority = 1,
+ .probe = intelhfi_hmp_capacity_provider_probe,
+ .init = intelhfi_hmp_capacity_provider_init,
+};
+HMP_CAPACITY_PROVIDER_DECLARE(intelhfi, intelhfi_hmp_capacity_provider);
+#endif /* HMP */
+
+/*
+ * HMP score setter
+ * (Available only if HMP options are define in kernel configuration.)
+ */
+#ifdef HMP
+static void
+intelhfi_hmp_score_initial_flag_set(void)
+{
+ struct cpu_group *cg;
+ struct hmp_pcpu *hp;
+
+ cg = cpu_top->cg_child;
+ KASSERT(cg != NULL, ("CPU topology is single."));
+
+ for (int grp=0; grp<ihfi_inst.cpugroups; grp++, cg++) {
+
+ for (uint32_t cid=cg->cg_first; cid<=cg->cg_last; cid++) {
+ hp = DPCPU_ID_PTR(cid, hmp_pcpu);
+ KASSERT(hp != NULL, ("DPCPU area is NULL."));
+
+ hmp_set_flags(hp, HMP_FLAG_DYNAMIC);
+ }
+ }
+}
+
+static void
+intelhfi_hmp_score_set(struct intelhfi_instance *inst)
+{
+ uint8_t *capflags, *entry;
+ struct cpu_group *cg;
+ struct hmp_pcpu *hp;
+
+ /* Check change flag in Global header */
+ capflags = (uint8_t *)(inst->cache.ptr) + sizeof(uint64_t);
+ if (!(*(capflags+0) & INTELHFI_GH_FLAG_REPORT)
+ && !(*(capflags+1) & INTELHFI_GH_FLAG_REPORT))
+ return;
+
+ entry = (uint8_t *)(inst->cache.ptr) + inst->hdrsize;
+ cg = cpu_top->cg_child;
+ KASSERT(cg != NULL, ("CPU topology is single."));
+
+ for (int grp=0; grp<inst->cpugroups; grp++, entry+=inst->entrysize, cg++) {
+
+ for (uint32_t cid=cg->cg_first; cid<=cg->cg_last; cid++) {
+ hp = DPCPU_ID_PTR(cid, hmp_pcpu);
+ KASSERT(hp != NULL, ("DPCPU area is NULL."));
+
+ if (*(capflags+0) & INTELHFI_GH_FLAG_REPORT) {
+ hmp_set_score(hp, HMP_SCORE_PERF, INTELHFI_HMP_SCORE_FROM(*(entry+0)));
+
+ /* Check & trim HMP throttled flag */
+ if (hmp_flag(hp, HMP_FLAG_THROTTLED) && (*(entry+0)>0))
+ hmp_set_flags(hp, HMP_FLAG_DYNAMIC);
+ else if (*(entry+0) == 0)
+ hmp_set_flags(hp, HMP_FLAG_DYNAMIC|HMP_FLAG_THROTTLED);
+ }
+
+ if (*(capflags+1) & INTELHFI_GH_FLAG_REPORT)
+ hmp_set_score(hp, HMP_SCORE_EFF, INTELHFI_HMP_SCORE_FROM(*(entry+1)));
+ }
+ }
+}
+#endif /* HMP */
+
+/*
+ * LVT thermal interrupts handler
+ */
+static void
+intelhfi_get_hwtable(struct intelhfi_instance *inst)
+{
+ uint64_t msr_status;
+
+ KASSERT(inst != NULL, ("%s: instance ptr. is NULL.", __func__));
+
+ if (! mtx_trylock_spin(&inst->intr_lock))
+ return;
+
+ /* Check HFI/ITD update status */
+ msr_status = rdmsr(MSR_IA32_PKG_THERM_STATUS);
+ if (msr_status & IA32_PKG_THERM_STATUS_HFI_UPDATED) {
+
+ /* Check HFI/ITD update's timestamp and Copy HFI/ITD HW table to local cache */
+ if (*(inst->cache.timestamp) != *(inst->hwtable.timestamp))
+ memcpy(inst->cache.ptr, inst->hwtable.ptr, inst->tblsize);
+
+#ifdef HMP
+ if (inst->status & INTELHFI_STATUS_USEHMP)
+ intelhfi_hmp_score_set(inst);
+#endif /* HMP */
+
+ /* Clear HFI/ITD update's flag on MSR */
+ msr_status &= ~IA32_PKG_THERM_STATUS_HFI_UPDATED;
+ wrmsr(MSR_IA32_PKG_THERM_STATUS, msr_status);
+ }
+
+ mtx_unlock_spin(&inst->intr_lock);
+}
+
+static void
+intelhfi_interrupt(int cpu, void *value)
+{
+ intelhfi_get_hwtable((struct intelhfi_instance *)value);
+}
+
+/*
+ * intelhfi driver probe & initialization
+ */
+static int
+intelhfi_device_check(void)
+{
+ u_int regs[4];
+
+ /* Check Intel CPU */
+ if (cpu_high < 6 || cpu_vendor_id != CPU_VENDOR_INTEL)
+ return (-1);
+
+ /* Get CPUID Leaf 6 */
+ do_cpuid(0x06, regs);
+
+ /* Check Intel Hardware Feedback & Thread Director feature */
+ if( !(regs[0] & CPUTPM1_HW_FEEDBACK) && !(regs[0] & CPUTPM1_THREAD_DIRECTOR))
+ return (-2);
+
+ /* Check performance reporting features */
+ if (!(regs[3] & CPUID_HF_PERFORMANCE))
+ return (-3);
+
+ /* Check efficiency reporting features */
+ if (!(regs[3] & CPUID_HF_EFFICIENCY))
+ return (-4);
+
+ return (0);
+}
+
+static int
+intelhfi_device_init(void)
+{
+ int ret = 0;
+ u_int regs[4];
+ uint64_t msrval;
+ uint8_t capabilities;
+ uint8_t classes;
+ void *mapptr;
+
+ /* Check intelhfi loaded */
+ if (ihfi_inst.status & INTELHFI_STATUS_LOADED)
+ return ((ihfi_inst.status & INTELHFI_STATUS_USEHMP) ? 0 : 1);
+
+ /* Check exist Intel HFI/TD */
+ if (intelhfi_device_check())
+ return (2);
+
+ /* Get CPUID Leaf 6 */
+ do_cpuid(0x06, regs);
+
+ /* Check & Get ITD capabilites (CP) */
+ capabilities = 2;
+ if (regs[0] & CPUTPM1_THREAD_DIRECTOR) {
+ capabilities = __builtin_popcount(regs[3] & CPUID_TD_CAPABLITIES);
+
+ if (capabilities != 2) {
+ printf("intelhfi: Not support other than 2 capablities. - disable HFI/ITD.\n");
+ return (3);
+ }
+ }
+
+ /* Check & Get ITD classes (CL) */
+ classes = 1;
+ if (regs[0] & CPUTPM1_THREAD_DIRECTOR) {
+ classes = CPUID_LEAF6_ECX_CLASSES(regs[2]);
+
+ if (classes != 4) {
+ printf("intelhfi: Not support other than 4 classes. - fallback to HFI.\n");
+ classes = 1;
+ }
+ }
+
+ /* Set Intel Hardware Feedback & Thread Director feature flags */
+ if (regs[0] & CPUTPM1_THREAD_DIRECTOR)
+ ihfi_inst.flags.thdirector = 1;
+ if (regs[0] & CPUTPM1_HW_FEEDBACK)
+ ihfi_inst.flags.hfi = 1;
+
+ /* Set Intel Hardware Feedback & Thread Director settings */
+ ihfi_inst.capabilities = capabilities;
+ ihfi_inst.classes = classes;
+
+ /* Get CPU groups */
+ ihfi_inst.cpugroups = cpu_top->cg_children;
+
+ /* Calc. Header & Entry size */
+ ihfi_inst.hdrsize = ROUNDUP8((capabilities * classes)+8);
+ ihfi_inst.entrysize = ROUNDUP8(capabilities * classes);
+ ihfi_inst.tblsize = ROUNDUP8(ihfi_inst.hdrsize + (ihfi_inst.entrysize * ihfi_inst.cpugroups));
+
+ /* Alloc Cache page */
+ ihfi_inst.allocsize = (CPUID_LEAF6_EDX_TBLPAGES(regs[3]) + 1) * PAGE_SIZE;
+ ihfi_inst.cache.ptr = malloc(ihfi_inst.allocsize, M_INTELHFI, M_NOWAIT | M_ZERO);
+ if (ihfi_inst.cache.ptr == NULL) {
+ printf("intelhfi: Not enough memory for local table cache. - disable HFI/ITD.\n");
+ ret = (4);
+ goto scrinit_err1;
+ }
+
+ /* Init. spin-lock structure */
+ mtx_init(&ihfi_inst.intr_lock, "intelhfi Interrupt lock", NULL, MTX_SPIN);
+
+ /* Enable Intel ThreadDirector features for each Core */
+ x86_msr_op(MSR_IA32_HW_FEEDBACK_THREAD_CONFIG, MSR_OP_RENDEZVOUS_ALL | MSR_OP_READ,
+ 0, &msrval);
+ x86_msr_op(MSR_IA32_HW_FEEDBACK_THREAD_CONFIG, MSR_OP_RENDEZVOUS_ALL | MSR_OP_WRITE,
+ msrval | 1ULL, NULL);
+
+ /* Set Hardware feedback interface table */
+ msrval = rdmsr(MSR_IA32_HW_FEEDBACK_PTR);
+ if (msrval == 0) {
+ /* Alloc HFI page */
+ ihfi_inst.hwtable.ptr = kmem_alloc_contig(ihfi_inst.allocsize, M_NOWAIT | M_ZERO, 0,
+ BUS_SPACE_MAXADDR, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT );
+ if (ihfi_inst.hwtable.ptr == NULL) {
+ printf("intelhfi: Not enough memory for Hardware table. - disable HFI/ITD.\n");
+ ret = (5);
+ goto scrinit_err2;
+ }
+
+ ihfi_inst.flags.pmaped = 0;
+
+ /* Set HFI memory page to MSR_IA32_HW_FEEDBACK_PTR MSR */
+ msrval = (uint64_t)vtophys(ihfi_inst.hwtable.ptr) | IA32_HW_FEEDBACK_PTR_ENABLE;
+ wrmsr(MSR_IA32_HW_FEEDBACK_PTR, msrval);
+ } else {
+ /* Mapping hardware feedback table physical page to kernel memory. */
+ mapptr = pmap_mapdev((msrval & ~IA32_HW_FEEDBACK_PTR_ENABLE), ihfi_inst.allocsize);
+ if (NULL == mapptr) {
+ printf("intelhfi: Not enough memory for Hardware mapping table. - disable HFI/ITD.\n");
+ ret = (6);
+ goto scrinit_err2;
+ }
+
+ ihfi_inst.flags.pmaped = 1;
+ ihfi_inst.hwtable.ptr = mapptr;
+ }
+
+ /* Regist sysctl interfaces */
+ if (intelhfi_regist_sysctl()) {
+ ret = (7);
+ goto scrinit_err3;
+ }
+
+ /* Enable HFI & Thread Director to MSR_IA32_HW_FEEDBACK_CONFIG MSR */
+ msrval = rdmsr(MSR_IA32_HW_FEEDBACK_CONFIG);
+ if (ihfi_inst.flags.hfi)
+ msrval |= IA32_HW_FEEDBACK_CONFIG_EN_HFI;
+ if (ihfi_inst.flags.thdirector)
+ msrval |= IA32_HW_FEEDBACK_CONFIG_EN_THDIR;
+ wrmsr(MSR_IA32_HW_FEEDBACK_CONFIG, msrval);
+
+#ifdef HMP
+ /* Set HMP Dynamic flag */
+ if (ihfi_inst.status & INTELHFI_STATUS_USEHMP)
+ intelhfi_hmp_score_initial_flag_set();
+#endif /* HMP */
+
+ /* Init. copy Hardware feedback table to cache table when reload this module. */
+ if (ihfi_inst.flags.pmaped)
+ memcpy(ihfi_inst.cache.ptr, ihfi_inst.hwtable.ptr, ihfi_inst.allocsize);
+
+ /* Enable Local APIC thermal interrupt handle */
+ lapic_enable_thermal(intelhfi_interrupt, (void *)&ihfi_inst);
+
+ /* Set intelhfi loaded flag */
+ ihfi_inst.status |= INTELHFI_STATUS_LOADED;
+
+ printf("intelhfi: Intel(R) Hardware-Feedback Interface\n");
+
+ /* Enable HFI/ITD interrupt */
+ msrval = rdmsr(MSR_IA32_PKG_THERM_INTERRUPT) | IA32_PKG_THERM_INTERRUPT_HFI_ENABLE;
+ wrmsr(MSR_IA32_PKG_THERM_INTERRUPT, msrval);
+
+ return (0);
+
+scrinit_err3:
+ /* Unmap Hardware feedback table physical page area */
+ if (ihfi_inst.flags.pmaped) {
+ pmap_unmapdev(ihfi_inst.hwtable.ptr, ihfi_inst.allocsize);
+ ihfi_inst.hwtable.ptr = NULL;
+ }
+
+scrinit_err2:
+ /* Destroy spin-lock structure */
+ mtx_destroy(&ihfi_inst.intr_lock);
+
+scrinit_err1:
+ /* Free cache area */
+ if (ihfi_inst.cache.ptr != NULL) {
+ free(ihfi_inst.cache.ptr, M_INTELHFI);
+ ihfi_inst.cache.ptr = NULL;
+ }
+
+ return (ret);
+}
+
+/*
+ * intelhfi driver initialization via SYSINIT
+ * (Available only if HMP option is NOT defined and
+ * "device intelhfi" is defined in kernel configuration.)
+ */
+#if !defined(HMP) && defined(DEV_INTELHFI)
+static void
+intelhfi_sysinit(void *arg __unused)
+{
+ intelhfi_device_init();
+}
+SYSINIT(intelhfi, SI_SUB_SMP + 2, SI_ORDER_ANY, intelhfi_sysinit, NULL);
+#endif /* !HMP & INTELHFI */
+
+/*
+ * HMP socre provider
+ * (Available only if HMP options are define in kernel configuration.)
+ */
+#ifdef HMP
+static int
+intelhfi_hmp_score_provider_probe(void)
+{
+ return intelhfi_device_check();
+}
+
+static int
+intelhfi_hmp_score_provider_init(void)
+{
+ return intelhfi_device_init();
+}
+
+static struct hmp_score_provider intelhfi_hmp_score_provider = {
+ .name = INTELHFI_NAME,
+ .priority = 1,
+ .probe = intelhfi_hmp_score_provider_probe,
+ .init = intelhfi_hmp_score_provider_init,
+};
+HMP_SCORE_PROVIDER_DECLARE(intelhfi, intelhfi_hmp_score_provider);
+#endif /* HMP */
+
+/*
+ * Module Interfaces
+ */
+static int
+intelhfi_device_remove(void)
+{
+ uint64_t msr_intr;
+
+ /* Check intelhfi NOT loaded */
+ if (!(ihfi_inst.status & INTELHFI_STATUS_LOADED))
+ return (1);
+
+ /* Remove sysctl interface */
+ intelhfi_remove_sysctl();
+
+ /* Disable HFI/ITD interrupt */
+ msr_intr = rdmsr(MSR_IA32_PKG_THERM_INTERRUPT);
+ msr_intr &= ~IA32_PKG_THERM_INTERRUPT_HFI_ENABLE;
+ wrmsr(MSR_IA32_PKG_THERM_INTERRUPT, msr_intr);
+
+ /* Disable Local APIC thermal interrupt handle */
+ /* TODO:
+ * Currently, Local APIC thermal interrupt handler is only used
+ * by this driver, so Local APIC thermal interrupt is disabled, but
+ * if other drivers are used in the future, instead of disabling Local
+ * APIC thermal interrupt itself, it will be necessary to disable the
+ * interrupt handler of this driver. Must make sure to unregister.
+ */
+ lapic_disable_thermal();
+
+ /* Unmap Hardware feedback table physical page area */
+ if (ihfi_inst.flags.pmaped) {
+ pmap_unmapdev(ihfi_inst.hwtable.ptr, ihfi_inst.allocsize);
+ ihfi_inst.hwtable.ptr = NULL;
+ }
+
+ /*
+ * The physical address set for MSR_IA32_HW_FEEDBACK_PTR MSR and the enable
+ * flag set for MSR_IA32_HW_FEEDBACK_CONFIG MSR should also be disabled,
+ * but the current CPU implementation is that the physical address once
+ * set for MSR_IA32_HW_FEEDBACK_PTR MSR remains inside the CPU even after
+ * being disabled.
+ * For this reason, We have not intentionally disabled them at this time.
+ */
+
+ /* Destroy spin-lock structure */
+ mtx_destroy(&ihfi_inst.intr_lock);
+
+ /* Free cache area */
+ if (ihfi_inst.cache.ptr != NULL) {
+ free(ihfi_inst.cache.ptr, M_INTELHFI);
+ ihfi_inst.cache.ptr = NULL;
+ }
+
+ /* Clear intelhfi loaded flag */
+ ihfi_inst.status &= ~INTELHFI_STATUS_LOADED;
+
+ return (0);
+}
+
+static int
+intelhfi_modevent(module_t mod, int type, void *data)
+{
+ switch (type) {
+ case MOD_LOAD:
+#ifdef DEV_INTELHFI
+ /*
+ * If intelhfi is defined in the kernel configuration and initialized
+ * via HMP or SYSINIT at boot time, it is intentionally returned as 0
+ * to prevent subsequent dynamic loading by the user.
+ */
+ return (0);
+#else
+ return intelhfi_device_init();
+#endif /* DEV_INTELHFI */
+
+ case MOD_UNLOAD:
+#ifdef HMP
+ /* If used from HMP, dynamic unloading must be disabled. */
+ if (ihfi_inst.status & INTELHFI_STATUS_USEHMP)
+ return (EBUSY);
+#endif /* HMP */
+ return intelhfi_device_remove();
+
+ default:
+ return (EOPNOTSUPP);
+ }
+}
+
+static moduledata_t intelhfi_mod = {
+ INTELHFI_NAME, /* module name */
+ intelhfi_modevent, /* event handler */
+ NULL
+};
+DECLARE_MODULE(intelhfi, intelhfi_mod, SI_SUB_SMP + 2, SI_ORDER_ANY);
+
+/*
+ * Sysctls
+ */
+static int
+intelhfi_sysctl_printtable(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf *buf;
+ uint8_t *entry;
+ int err;
+ struct cpu_group *cg;
+
+ buf = sbuf_new_for_sysctl(NULL, NULL, 512, req);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ sbuf_printf(buf, "\nintelhfi: [HFI/ITD table] TimeStamp=%lx\n", *(ihfi_inst.cache.timestamp));
+
+ sbuf_cat(buf, " ");
+ for(int cl=0; cl<ihfi_inst.classes; cl++)
+ sbuf_printf(buf, " Class %d ", cl);
+
+ sbuf_cat(buf, "\n---------");
+ for(int cl=0; cl<ihfi_inst.classes; cl++)
+ sbuf_cat(buf, " Perf: Eff");
+
+ cg = cpu_top->cg_child;
+ KASSERT(cg != NULL, ("CPU topology is single."));
+
+ for(int grp=0; grp<ihfi_inst.cpugroups; grp++) {
+ entry = (uint8_t *)ihfi_inst.cache.ptr + ihfi_inst.hdrsize + (grp * ihfi_inst.entrysize);
+
+ sbuf_printf(buf, "\n Grp %2d:", grp);
+
+ for(int cl=0; cl<ihfi_inst.classes; cl++, entry+=2)
+ sbuf_printf(buf, " %3d : %3d", *(entry+0), *(entry+1));
+
+ if (cg->cg_first != cg->cg_last)
+ sbuf_printf(buf, " (Core #%d - #%d)", cg->cg_first, cg->cg_last);
+ else
+ sbuf_printf(buf, " (Core #%d)", cg->cg_first);
+
+ cg++;
+ }
+
+ err = sbuf_finish(buf);
+
+ sbuf_delete(buf);
+
+ return (err);
+}
+
+static int
+intelhfi_sysctl_dumptable(SYSCTL_HANDLER_ARGS)
+{
+ struct sbuf *buf;
+ uint8_t *p;
+ int err;
+
+ buf = sbuf_new_for_sysctl(NULL, NULL, 512, req);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ sbuf_printf(buf, "\nintelhfi: [Dump HFI/ITD table] TimeStamp=%lx\n",
+ *(ihfi_inst.hwtable.timestamp));
+ sbuf_printf(buf, " Capacity=%u, Class=%u\n",
+ ihfi_inst.capabilities, ihfi_inst.classes);
+
+ sbuf_printf(buf, "\n Table Dump -- Size:%u\n ", ihfi_inst.tblsize);
+ p = (uint8_t *)ihfi_inst.hwtable.ptr;
+ for(uint32_t cur=1; cur<=ihfi_inst.tblsize; cur++, p++) {
+ sbuf_printf(buf, "0x%02x,", *p);
+ if ((cur%16)==0)
+ sbuf_printf(buf, "\n ");
+ }
+
+ err = sbuf_finish(buf);
+
+ sbuf_delete(buf);
+
+ return (err);
+}
+
+static int
+intelhfi_regist_sysctl(void)
+{
+ sysctl_ctx_init(&(ihfi_inst.sysctl.ctx));
+
+ ihfi_inst.sysctl.oid = SYSCTL_ADD_NODE( &(ihfi_inst.sysctl.ctx),
+ SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, INTELHFI_NAME,
+ CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "Intel(R) Hardware-Feedback Interface state");
+
+ if (ihfi_inst.sysctl.oid == NULL)
+ return (-1);
+
+ SYSCTL_ADD_PROC( &(ihfi_inst.sysctl.ctx), SYSCTL_CHILDREN(ihfi_inst.sysctl.oid),
+ OID_AUTO, "printtable", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, intelhfi_sysctl_printtable, "A", "Printout HFI/ITD HW table.");
+
+ SYSCTL_ADD_PROC( &(ihfi_inst.sysctl.ctx), SYSCTL_CHILDREN(ihfi_inst.sysctl.oid),
+ OID_AUTO, "dumptable", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ NULL, 0, intelhfi_sysctl_dumptable, "A", "[DEBUG] Dump HFI/ITD HW table.");
+
+ return (0);
+}
+
+static void
+intelhfi_remove_sysctl(void)
+{
+ sysctl_ctx_free(&(ihfi_inst.sysctl.ctx));
+}
+
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -175,6 +175,7 @@
${_igc} \
imgact_binmisc \
${_imx} \
+ ${_intelhfi} \
${_intelspi} \
${_io} \
${_ioat} \
@@ -822,6 +823,7 @@
_hyperv= hyperv
_ichwd= ichwd
_ida= ida
+_intelhfi= intelhfi
_intelspi= intelspi
_ips= ips
_isci= isci
diff --git a/sys/modules/intelhfi/Makefile b/sys/modules/intelhfi/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/intelhfi/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/dev/intelhfi
+
+KMOD= intelhfi
+SRCS= intelhfi.c bus_if.h device_if.h opt_intelhfi.h
+
+.include <bsd.kmod.mk>

File Metadata

Mime Type
text/plain
Expires
Mon, May 18, 2:57 PM (13 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33253011
Default Alt Text
D44456.id177533.diff (22 KB)

Event Timeline