Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F156953001
D44456.id177533.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
22 KB
Referenced Files
None
Subscribers
None
D44456.id177533.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D44456: intelhfi - Intel TD/HFI driver - Part4: Add intelhfi driver's source-code & Makefile.
Attached
Detach File
Event Timeline
Log In to Comment