From 881f7bffbf5c93279c3f44045887e049cd4ae842 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sun, 29 Mar 2015 20:26:36 +0800 Subject: [PATCH] dimm: Implement pseudo device driver for DIMM related drivers - This pseudo device driver installs sensor device for DIMM related sensors (memtemp(4) and upcoming ecc(4) changes). - This pseudo device driver keeps DIMM location information. And the location information is exposed through a new sysctl tree, hw.dimminfo. The nodes in this sysctl tree have the same names as the sensor devices, so that programatic way could be used to report DIMM status. - This pseudo device implements common sensor update function for memtemp(4). And it keeps configurable temperature thresholds for memtemp(4) sensor. - Utilize this pseudo device driver in memtemp(4). --- share/man/man4/memtemp.4 | 34 ++- sys/conf/files | 1 + sys/config/LINT64 | 2 + sys/config/X86_64_GENERIC | 3 +- sys/dev/misc/Makefile | 2 +- sys/dev/misc/dimm/Makefile | 4 + sys/dev/misc/dimm/dimm.c | 280 ++++++++++++++++++++++++ sys/dev/misc/dimm/dimm.h | 53 +++++ sys/dev/powermng/memtemp/memtemp_core.c | 29 +-- sys/dev/powermng/memtemp/memtemp_e5.c | 122 +++++------ 10 files changed, 434 insertions(+), 96 deletions(-) create mode 100644 sys/dev/misc/dimm/Makefile create mode 100644 sys/dev/misc/dimm/dimm.c create mode 100644 sys/dev/misc/dimm/dimm.h diff --git a/share/man/man4/memtemp.4 b/share/man/man4/memtemp.4 index 9406411c37..1437f9c4b5 100644 --- a/share/man/man4/memtemp.4 +++ b/share/man/man4/memtemp.4 @@ -28,7 +28,7 @@ .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 12, 2015 +.Dd April 4, 2015 .Dt MEMTEMP 4 .Os .Sh NAME @@ -38,6 +38,7 @@ To compile this driver into the kernel, place the following lines in your kernel configuration file: .Bd -ragged -offset indent +.Cd "device dimm" .Cd "device coremctl" .Cd "device memtemp" .Ed @@ -58,15 +59,28 @@ The values are exposed through the tree. For example: .Bd -literal -offset indent -%sysctl hw.sensors -hw.sensors.dimm0.temp0: 39.00 degC -hw.sensors.dimm3.temp0: 40.00 degC -hw.sensors.dimm6.temp0: 35.00 degC -hw.sensors.dimm9.temp0: 33.00 degC -hw.sensors.dimm12.temp0: 29.00 degC -hw.sensors.dimm15.temp0: 35.00 degC -hw.sensors.dimm18.temp0: 33.00 degC -hw.sensors.dimm21.temp0: 31.00 degC +% sysctl hw.sensors +hw.sensors.dimm0.temp0: 40.00 degC (node0 chan0 DIMM0), OK +hw.sensors.dimm1.temp0: 39.00 degC (node0 chan1 DIMM0), OK +.Ed +.Pp +The DIMM location and configurable critical temperature thresholds +are exposed through hw.dimminfo +.Xr sysctl 3 +tree. +For example: +.Bd -literal -offset indent +% sysctl hw.dimminfo +hw.dimminfo.dimm0.node: 0 +hw.dimminfo.dimm0.chan: 0 +hw.dimminfo.dimm0.slot: 0 +hw.dimminfo.dimm0.temp_hiwat: 93 +hw.dimminfo.dimm0.temp_lowat: 88 +hw.dimminfo.dimm1.node: 0 +hw.dimminfo.dimm1.chan: 1 +hw.dimminfo.dimm1.slot: 0 +hw.dimminfo.dimm1.temp_hiwat: 93 +hw.dimminfo.dimm1.temp_lowat: 88 .Ed .Sh HARDWARE The diff --git a/sys/conf/files b/sys/conf/files index 1635958dab..e6d430fcd8 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1745,6 +1745,7 @@ bus/isa/pnpeat.c optional isa dev/misc/amdsbwd/amdsbwd.c optional amdsbwd dev/misc/coremctl/coremctl.c optional coremctl dev/misc/coremctl/coremctl_if.m optional coremctl +dev/misc/dimm/dimm.c optional dimm dev/misc/ecc/ecc_amd8000.c optional ecc dev/misc/ecc/ecc_e3.c optional ecc dev/misc/ecc/ecc_e5.c optional ecc diff --git a/sys/config/LINT64 b/sys/config/LINT64 index 25623ebdd2..eb989f03fc 100644 --- a/sys/config/LINT64 +++ b/sys/config/LINT64 @@ -1270,6 +1270,7 @@ options SND_OLDSTEREO # # bktr: Brooktree bt848/848a/849a/878/879 video capture and TV Tuner board # coremctl: Intel Core/E3 memory controller (required by ecc(4)) +# dimm: Location inforamtion (required by memtemp(4)) # ecc: ECC memory controller # ipmi: Intelligent Platform Management Interface # joy: joystick @@ -1286,6 +1287,7 @@ options SND_OLDSTEREO # The cards can use an IRQ of 11, 12 or 15. device coremctl +device dimm device ecc device joy0 at isa? port IO_GAME device nrp diff --git a/sys/config/X86_64_GENERIC b/sys/config/X86_64_GENERIC index 59e81bbaab..157ac9c07f 100644 --- a/sys/config/X86_64_GENERIC +++ b/sys/config/X86_64_GENERIC @@ -185,12 +185,13 @@ device wbsio1 at isa? port 0x4e device lm#3 at wbsio? # Intel Core and newer CPUs on-die digital thermal sensor support device coretemp +device dimm # DIMM information (location, etc.) device coremctl # support Intel Core and E3 memory controller device ecc # support AMD8000, Intel E3 and Intel E5 ECC # requires coremctl. device memtemp # support Intel Core, E3 and E5 memory thermal # sensor. - # requires coremctl. + # requires coremctl and dimm. # PCCARD (PCMCIA) support device pccard diff --git a/sys/dev/misc/Makefile b/sys/dev/misc/Makefile index c041cc24d2..c75dcf1aa1 100644 --- a/sys/dev/misc/Makefile +++ b/sys/dev/misc/Makefile @@ -1,4 +1,4 @@ SUBDIR= amdsbwd cmx cpuctl dcons ecc ichwd ipmi joy kbdmux lpbb \ - nmdm pcfclock putter snp syscons tbridge coremctl + nmdm pcfclock putter snp syscons tbridge coremctl dimm .include diff --git a/sys/dev/misc/dimm/Makefile b/sys/dev/misc/dimm/Makefile new file mode 100644 index 0000000000..b887ef107b --- /dev/null +++ b/sys/dev/misc/dimm/Makefile @@ -0,0 +1,4 @@ +KMOD= dimm +SRCS= dimm.c device_if.h bus_if.h + +.include diff --git a/sys/dev/misc/dimm/dimm.c b/sys/dev/misc/dimm/dimm.c new file mode 100644 index 0000000000..8fd0dac1bc --- /dev/null +++ b/sys/dev/misc/dimm/dimm.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2015 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Sepherosa Ziehau + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DIMM_TEMP_HIWAT_DEFAULT 85 +#define DIMM_TEMP_LOWAT_DEFAULT 75 + +struct dimm_softc { + TAILQ_ENTRY(dimm_softc) dimm_link; + int dimm_node; + int dimm_chan; + int dimm_slot; + int dimm_temp_hiwat; + int dimm_temp_lowat; + int dimm_id; + int dimm_ref; + + struct ksensordev dimm_sensdev; + uint32_t dimm_sens_taskflags; /* DIMM_SENS_TF_ */ + + struct sysctl_ctx_list dimm_sysctl_ctx; + struct sysctl_oid *dimm_sysctl_tree; +}; +TAILQ_HEAD(dimm_softc_list, dimm_softc); + +#define DIMM_SENS_TF_TEMP_CRIT 0x1 + +static void dimm_mod_unload(void); + +/* In the ascending order of dimm_softc.dimm_id */ +static struct dimm_softc_list dimm_softc_list; + +static SYSCTL_NODE(_hw, OID_AUTO, dimminfo, CTLFLAG_RD, NULL, + "DIMM information"); + +struct dimm_softc * +dimm_create(int node, int chan, int slot) +{ + struct dimm_softc *sc, *after = NULL; + int dimm_id = 0; + + SYSCTL_XLOCK(); + + TAILQ_FOREACH(sc, &dimm_softc_list, dimm_link) { + /* + * Already exists; done. + */ + if (sc->dimm_node == node && sc->dimm_chan == chan && + sc->dimm_slot == slot) { + KASSERT(sc->dimm_ref > 0, ("invalid dimm reference %d", + sc->dimm_ref)); + sc->dimm_ref++; + SYSCTL_XUNLOCK(); + return sc; + } + + /* + * Find the lowest usable id. + */ + if (sc->dimm_id == dimm_id) { + ++dimm_id; + after = sc; + } + } + + sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); + sc->dimm_node = node; + sc->dimm_chan = chan; + sc->dimm_slot = slot; + sc->dimm_id = dimm_id; + sc->dimm_ref = 1; + sc->dimm_temp_hiwat = DIMM_TEMP_HIWAT_DEFAULT; + sc->dimm_temp_lowat = DIMM_TEMP_LOWAT_DEFAULT; + + ksnprintf(sc->dimm_sensdev.xname, sizeof(sc->dimm_sensdev.xname), + "dimm%d", sc->dimm_id); + + /* + * Create sysctl tree for the location information. Use + * same name as the sensor device. + */ + sysctl_ctx_init(&sc->dimm_sysctl_ctx); + sc->dimm_sysctl_tree = SYSCTL_ADD_NODE(&sc->dimm_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw_dimminfo), OID_AUTO, + sc->dimm_sensdev.xname, CTLFLAG_RD, 0, ""); + if (sc->dimm_sysctl_tree != NULL) { + SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx, + SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO, + "node", CTLFLAG_RD, &sc->dimm_node, 0, + "CPU node of this DIMM"); + SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx, + SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO, + "chan", CTLFLAG_RD, &sc->dimm_chan, 0, + "channel of this DIMM"); + SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx, + SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO, + "slot", CTLFLAG_RD, &sc->dimm_slot, 0, + "slot of this DIMM"); + SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx, + SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO, + "temp_hiwat", CTLFLAG_RW, &sc->dimm_temp_hiwat, 0, + "Raise alarm once DIMM temperature is above this value " + "(unit: C)"); + SYSCTL_ADD_INT(&sc->dimm_sysctl_ctx, + SYSCTL_CHILDREN(sc->dimm_sysctl_tree), OID_AUTO, + "temp_lowat", CTLFLAG_RW, &sc->dimm_temp_lowat, 0, + "Cancel alarm once DIMM temperature is below this value " + "(unit: C)"); + } + + if (after == NULL) { + KKASSERT(sc->dimm_id == 0); + TAILQ_INSERT_HEAD(&dimm_softc_list, sc, dimm_link); + } else { + TAILQ_INSERT_AFTER(&dimm_softc_list, after, sc, dimm_link); + } + + sensordev_install(&sc->dimm_sensdev); + + SYSCTL_XUNLOCK(); + return sc; +} + +int +dimm_destroy(struct dimm_softc *sc) +{ + SYSCTL_XLOCK(); + + KASSERT(sc->dimm_ref > 0, ("invalid dimm reference %d", sc->dimm_ref)); + sc->dimm_ref--; + if (sc->dimm_ref > 0) { + SYSCTL_XUNLOCK(); + return EAGAIN; + } + + sensordev_deinstall(&sc->dimm_sensdev); + + TAILQ_REMOVE(&dimm_softc_list, sc, dimm_link); + if (sc->dimm_sysctl_tree != NULL) + sysctl_ctx_free(&sc->dimm_sysctl_ctx); + kfree(sc, M_DEVBUF); + + SYSCTL_XUNLOCK(); + return 0; +} + +void +dimm_sensor_attach(struct dimm_softc *sc, struct ksensor *sens) +{ + sensor_attach(&sc->dimm_sensdev, sens); +} + +void +dimm_sensor_detach(struct dimm_softc *sc, struct ksensor *sens) +{ + sensor_detach(&sc->dimm_sensdev, sens); +} + +void +dimm_set_temp_thresh(struct dimm_softc *sc, int hiwat, int lowat) +{ + sc->dimm_temp_hiwat = hiwat; + sc->dimm_temp_lowat = lowat; +} + +void +dimm_sensor_temp(struct dimm_softc *sc, struct ksensor *sens, int temp) +{ + if (temp >= sc->dimm_temp_hiwat && + (sc->dimm_sens_taskflags & DIMM_SENS_TF_TEMP_CRIT) == 0) { + char temp_str[16], data[64]; + + ksnprintf(temp_str, sizeof(temp_str), "%d", temp); + ksnprintf(data, sizeof(data), "node=%d channel=%d dimm=%d", + sc->dimm_node, sc->dimm_chan, sc->dimm_slot); + devctl_notify("memtemp", "Thermal", temp_str, data); + + kprintf("dimm%d: node%d channel%d DIMM%d " + "temperature (%dC) is too high (>= %dC)\n", + sc->dimm_id, sc->dimm_node, sc->dimm_chan, sc->dimm_slot, + temp, sc->dimm_temp_hiwat); + + sc->dimm_sens_taskflags |= DIMM_SENS_TF_TEMP_CRIT; + } else if ((sc->dimm_sens_taskflags & DIMM_SENS_TF_TEMP_CRIT) && + temp < sc->dimm_temp_lowat) { + sc->dimm_sens_taskflags &= ~DIMM_SENS_TF_TEMP_CRIT; + } + + if (sc->dimm_sens_taskflags & DIMM_SENS_TF_TEMP_CRIT) + sens->status = SENSOR_S_CRIT; + else + sens->status = SENSOR_S_OK; + sens->flags &= ~SENSOR_FINVALID; + sens->value = (temp * 1000000) + 273150000; +} + +static void +dimm_mod_unload(void) +{ + struct dimm_softc *sc; + + SYSCTL_XLOCK(); + + while ((sc = TAILQ_FIRST(&dimm_softc_list)) != NULL) { + int error; + + error = dimm_destroy(sc); + KASSERT(!error, ("dimm%d is still referenced, ref %d", + sc->dimm_id, sc->dimm_ref)); + } + + SYSCTL_XUNLOCK(); +} + +static int +dimm_mod_event(module_t mod, int type, void *unused) +{ + switch (type) { + case MOD_LOAD: + TAILQ_INIT(&dimm_softc_list); + return 0; + + case MOD_UNLOAD: + dimm_mod_unload(); + return 0; + + default: + return 0; + } +} + +static moduledata_t dimm_mod = { + "dimm", + dimm_mod_event, + 0 +}; +DECLARE_MODULE(dimm, dimm_mod, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY); +MODULE_VERSION(dimm, 1); diff --git a/sys/dev/misc/dimm/dimm.h b/sys/dev/misc/dimm/dimm.h new file mode 100644 index 0000000000..b5541d0606 --- /dev/null +++ b/sys/dev/misc/dimm/dimm.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Sepherosa Ziehau + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DEV_DIMM_H_ +#define _DEV_DIMM_H_ + +struct dimm_softc; +struct ksensor; + +struct dimm_softc *dimm_create(int _node, int _chan, int _slot); +int dimm_destroy(struct dimm_softc *_sc); +void dimm_sensor_attach(struct dimm_softc *_sc, + struct ksensor *_sens); +void dimm_sensor_detach(struct dimm_softc *_sc, + struct ksensor *_sens); + +void dimm_set_temp_thresh(struct dimm_softc *_sc, + int _hiwat, int _lowat); +void dimm_sensor_temp(struct dimm_softc *_sc, + struct ksensor *_sens, int _temp); + +#endif /* !_DEV_DIMM_H_ */ diff --git a/sys/dev/powermng/memtemp/memtemp_core.c b/sys/dev/powermng/memtemp/memtemp_core.c index d7efd9c83d..619e4b8e68 100644 --- a/sys/dev/powermng/memtemp/memtemp_core.c +++ b/sys/dev/powermng/memtemp/memtemp_core.c @@ -49,16 +49,18 @@ #include "pcib_if.h" #include +#include struct memtemp_core_softc; struct memtemp_core_dimm { TAILQ_ENTRY(memtemp_core_dimm) dimm_link; - struct ksensordev dimm_sensordev; struct ksensor dimm_sensor; struct memtemp_core_softc *dimm_parent; int dimm_reg; uint32_t dimm_mask; + + struct dimm_softc *dimm_softc; }; struct memtemp_core_type { @@ -112,6 +114,7 @@ DRIVER_MODULE(memtemp_core, coremctl, memtemp_core_driver, memtemp_devclass, NULL, NULL); MODULE_DEPEND(memtemp_core, pci, 1, 1, 1); MODULE_DEPEND(memtemp_core, coremctl, 1, 1, 1); +MODULE_DEPEND(memtemp_core, dimm, 1, 1, 1); static __inline uint32_t CSR_READ_4(struct memtemp_core_softc *sc, int ofs) @@ -211,7 +214,7 @@ memtemp_core_dimm_attach(struct memtemp_core_softc *sc, int chan, int dimm_id, int dimm_reg) { struct memtemp_core_dimm *dimm_sc; - int dimm_extid; + struct ksensor *sens; dimm_sc = kmalloc(sizeof(*dimm_sc), M_DEVBUF, M_WAITOK | M_ZERO); dimm_sc->dimm_parent = sc; @@ -223,13 +226,14 @@ memtemp_core_dimm_attach(struct memtemp_core_softc *sc, int chan, int dimm_id, dimm_sc->dimm_mask = MCH_CORE_DIMM_TEMP_DIMM1; } - dimm_extid = (chan * PCI_CORE_MEMCTL_CHN_DIMM_MAX) + dimm_id; - ksnprintf(dimm_sc->dimm_sensordev.xname, - sizeof(dimm_sc->dimm_sensordev.xname), "dimm%d", dimm_extid); - dimm_sc->dimm_sensor.type = SENSOR_TEMP; - sensor_attach(&dimm_sc->dimm_sensordev, &dimm_sc->dimm_sensor); - sensor_task_register(dimm_sc, memtemp_core_sensor_task, 2); - sensordev_install(&dimm_sc->dimm_sensordev); + dimm_sc->dimm_softc = dimm_create(0, chan, dimm_id); + + sens = &dimm_sc->dimm_sensor; + ksnprintf(sens->desc, sizeof(sens->desc), "chan%d DIMM%d", + chan, dimm_id); + sens->type = SENSOR_TEMP; + dimm_sensor_attach(dimm_sc->dimm_softc, sens); + sensor_task_register(dimm_sc, memtemp_core_sensor_task, 5); TAILQ_INSERT_TAIL(&sc->temp_dimm, dimm_sc, dimm_link); } @@ -243,8 +247,9 @@ memtemp_core_detach(device_t dev) while ((dimm_sc = TAILQ_FIRST(&sc->temp_dimm)) != NULL) { TAILQ_REMOVE(&sc->temp_dimm, dimm_sc, dimm_link); - sensordev_deinstall(&dimm_sc->dimm_sensordev); sensor_task_unregister(dimm_sc); + dimm_sensor_detach(dimm_sc->dimm_softc, &dimm_sc->dimm_sensor); + dimm_destroy(dimm_sc->dimm_softc); kfree(dimm_sc, M_DEVBUF); } @@ -255,13 +260,11 @@ static void memtemp_core_sensor_task(void *xdimm_sc) { struct memtemp_core_dimm *dimm_sc = xdimm_sc; - struct ksensor *sensor = &dimm_sc->dimm_sensor; uint32_t val; int temp; val = CSR_READ_4(dimm_sc->dimm_parent, dimm_sc->dimm_reg); temp = __SHIFTOUT(val, dimm_sc->dimm_mask); - sensor->flags &= ~SENSOR_FINVALID; - sensor->value = (temp * 1000000) + 273150000; + dimm_sensor_temp(dimm_sc->dimm_softc, &dimm_sc->dimm_sensor, temp); } diff --git a/sys/dev/powermng/memtemp/memtemp_e5.c b/sys/dev/powermng/memtemp/memtemp_e5.c index d5e78d5ac4..56344debb7 100644 --- a/sys/dev/powermng/memtemp/memtemp_e5.c +++ b/sys/dev/powermng/memtemp/memtemp_e5.c @@ -49,6 +49,7 @@ #include "pcib_if.h" +#include #include #include @@ -59,13 +60,12 @@ struct memtemp_e5_softc; struct memtemp_e5_dimm { TAILQ_ENTRY(memtemp_e5_dimm) dimm_link; - struct ksensordev dimm_sensordev; struct ksensor dimm_sensor; struct memtemp_e5_softc *dimm_parent; int dimm_id; - int dimm_temp_hiwat; - int dimm_temp_lowat; int dimm_flags; + + struct dimm_softc *dimm_softc; }; #define MEMTEMP_E5_DIMM_FLAG_CRIT 0x1 @@ -140,6 +140,7 @@ static driver_t memtemp_e5_driver = { static devclass_t memtemp_devclass; DRIVER_MODULE(memtemp_e5, pci, memtemp_e5_driver, memtemp_devclass, NULL, NULL); MODULE_DEPEND(memtemp_e5, pci, 1, 1, 1); +MODULE_DEPEND(memtemp_e5, dimm, 1, 1, 1); static int memtemp_e5_probe(device_t dev) @@ -159,7 +160,6 @@ memtemp_e5_probe(device_t dev) for (c = memtemp_e5_chans; c->desc != NULL; ++c) { if (c->did == did && c->slot == slot && c->func == func) { struct memtemp_e5_softc *sc = device_get_softc(dev); - char desc[128]; uint32_t cfg; int node; @@ -177,9 +177,7 @@ memtemp_e5_probe(device_t dev) if ((cfg & PCI_E5_IMC_THERMAL_CHN_TEMP_CFG_CLTT) == 0) break; - ksnprintf(desc, sizeof(desc), "%s node%d channel%d", - c->desc, node, c->chan_ext); - device_set_desc_copy(dev, desc); + device_set_desc(dev, c->desc); sc->temp_chan = c; sc->temp_node = node; @@ -224,8 +222,10 @@ memtemp_e5_attach(device_t dev) for (dimm = 0; dimm < PCI_E5_IMC_CHN_DIMM_MAX; ++dimm) { char temp_lostr[16], temp_midstr[16], temp_histr[16]; struct memtemp_e5_dimm *dimm_sc; - int dimm_extid, temp_lo, temp_mid, temp_hi; + int temp_lo, temp_mid, temp_hi; + int temp_hiwat, temp_lowat, has_temp_thresh = 1; uint32_t dimmmtr, temp_th; + struct ksensor *sens; dimmmtr = IMC_CTAD_READ_4(dev, sc->temp_chan, PCI_E5_IMC_CTAD_DIMMMTR(dimm)); @@ -266,34 +266,47 @@ memtemp_e5_attach(device_t dev) * so ignore TEMPLO here. */ if (temp_mid <= 0) { - if (temp_hi <= 0) - dimm_sc->dimm_temp_hiwat = MEMTEMP_E5_DIMM_TEMP_HIWAT; - else - dimm_sc->dimm_temp_hiwat = temp_hi; + if (temp_hi <= 0) { + temp_hiwat = MEMTEMP_E5_DIMM_TEMP_HIWAT; + has_temp_thresh = 0; + } else { + temp_hiwat = temp_hi; + } } else { - dimm_sc->dimm_temp_hiwat = temp_mid; + temp_hiwat = temp_mid; + } + if (temp_hiwat < MEMTEMP_E5_DIMM_TEMP_STEP) { + temp_hiwat = MEMTEMP_E5_DIMM_TEMP_HIWAT; + has_temp_thresh = 0; + } + temp_lowat = temp_hiwat - MEMTEMP_E5_DIMM_TEMP_STEP; + + if (bootverbose) { + device_printf(dev, "DIMM%d " + "temp_hi %s, temp_mid %s, temp_lo %s\n", dimm, + temp_histr, temp_midstr, temp_lostr); + } + + dimm_sc->dimm_softc = dimm_create(sc->temp_node, + sc->temp_chan->chan_ext, dimm); + + if (has_temp_thresh) { + if (bootverbose) { + device_printf(dev, "DIMM%d " + "hiwat %dC, lowat %dC\n", + dimm, temp_hiwat, temp_lowat); + } + dimm_set_temp_thresh(dimm_sc->dimm_softc, + temp_hiwat, temp_lowat); } - if (dimm_sc->dimm_temp_hiwat < MEMTEMP_E5_DIMM_TEMP_STEP) - dimm_sc->dimm_temp_hiwat = MEMTEMP_E5_DIMM_TEMP_HIWAT; - dimm_sc->dimm_temp_lowat = dimm_sc->dimm_temp_hiwat - - MEMTEMP_E5_DIMM_TEMP_STEP; - - device_printf(dev, "DIMM%d " - "temp_hi %s, temp_mid %s, temp_lo %s\n", dimm, - temp_histr, temp_midstr, temp_lostr); - device_printf(dev, "DIMM%d hiwat %dC, lowat %dC\n", dimm, - dimm_sc->dimm_temp_hiwat, dimm_sc->dimm_temp_lowat); - - dimm_extid = - (sc->temp_node * PCI_E5_IMC_CHN_MAX * PCI_E5_IMC_CHN_DIMM_MAX) + - (sc->temp_chan->chan_ext * PCI_E5_IMC_CHN_DIMM_MAX) + dimm; - ksnprintf(dimm_sc->dimm_sensordev.xname, - sizeof(dimm_sc->dimm_sensordev.xname), - "dimm%d", dimm_extid); - dimm_sc->dimm_sensor.type = SENSOR_TEMP; - sensor_attach(&dimm_sc->dimm_sensordev, &dimm_sc->dimm_sensor); - sensor_task_register(dimm_sc, memtemp_e5_sensor_task, 2); - sensordev_install(&dimm_sc->dimm_sensordev); + + sens = &dimm_sc->dimm_sensor; + ksnprintf(sens->desc, sizeof(sens->desc), + "node%d chan%d DIMM%d", + sc->temp_node, sc->temp_chan->chan_ext, dimm); + sens->type = SENSOR_TEMP; + dimm_sensor_attach(dimm_sc->dimm_softc, sens); + sensor_task_register(dimm_sc, memtemp_e5_sensor_task, 5); TAILQ_INSERT_TAIL(&sc->temp_dimm, dimm_sc, dimm_link); } @@ -309,8 +322,9 @@ memtemp_e5_detach(device_t dev) while ((dimm_sc = TAILQ_FIRST(&sc->temp_dimm)) != NULL) { TAILQ_REMOVE(&sc->temp_dimm, dimm_sc, dimm_link); - sensordev_deinstall(&dimm_sc->dimm_sensordev); sensor_task_unregister(dimm_sc); + dimm_sensor_detach(dimm_sc->dimm_softc, &dimm_sc->dimm_sensor); + dimm_destroy(dimm_sc->dimm_softc); kfree(dimm_sc, M_DEVBUF); } @@ -323,11 +337,10 @@ memtemp_e5_sensor_task(void *xdimm_sc) struct memtemp_e5_dimm *dimm_sc = xdimm_sc; struct ksensor *sensor = &dimm_sc->dimm_sensor; device_t dev = dimm_sc->dimm_parent->temp_dev; - int dimm = dimm_sc->dimm_id; uint32_t val; int temp, reg; - reg = PCI_E5_IMC_THERMAL_DIMMTEMPSTAT(dimm); + reg = PCI_E5_IMC_THERMAL_DIMMTEMPSTAT(dimm_sc->dimm_id); val = pci_read_config(dev, reg, 4); if (val & (PCI_E5_IMC_THERMAL_DIMMTEMPSTAT_TEMPHI | @@ -343,38 +356,5 @@ memtemp_e5_sensor_task(void *xdimm_sc) sensor->value = 0; return; } - - /* - * Some BIOSes will always turn on TEMPMID, so we rely on - * our own hiwat/lowat to send the notification. - */ - if (temp >= dimm_sc->dimm_temp_hiwat && - (dimm_sc->dimm_flags & MEMTEMP_E5_DIMM_FLAG_CRIT) == 0) { - int node, chan; - char temp_str[16], data[64]; - - node = dimm_sc->dimm_parent->temp_node; - chan = dimm_sc->dimm_parent->temp_chan->chan_ext; - - ksnprintf(temp_str, sizeof(temp_str), "%d", temp); - ksnprintf(data, sizeof(data), - "node=%d channel=%d dimm=%d", node, chan, dimm); - devctl_notify("memtemp", "Thermal", temp_str, data); - - device_printf(dev, "node%d channel%d DIMM%d " - "temperature (%dC) is too high (>= %d)\n", - node, chan, dimm, temp, dimm_sc->dimm_temp_hiwat); - - dimm_sc->dimm_flags |= MEMTEMP_E5_DIMM_FLAG_CRIT; - } else if ((dimm_sc->dimm_flags & MEMTEMP_E5_DIMM_FLAG_CRIT) && - temp < dimm_sc->dimm_temp_lowat) { - dimm_sc->dimm_flags &= ~MEMTEMP_E5_DIMM_FLAG_CRIT; - } - - if (dimm_sc->dimm_flags & MEMTEMP_E5_DIMM_FLAG_CRIT) - sensor->status = SENSOR_S_CRIT; - else - sensor->status = SENSOR_S_OK; - sensor->flags &= ~SENSOR_FINVALID; - sensor->value = (temp * 1000000) + 273150000; + dimm_sensor_temp(dimm_sc->dimm_softc, sensor, temp); } -- 2.41.0