superio+ncthwm: Add hardware monitoring support
Add support for the following chips: - Nuvoton NCT6779D - Nuvoton NCT6796D-E Reviewed by: imp Pull Request: https://github.com/freebsd/freebsd-src/pull/719
This commit is contained in:
committed by
Warner Losh
parent
8e6ea10c31
commit
350b7c3570
@@ -0,0 +1,53 @@
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd Apr 18, 2023
|
||||
.Dt NCTHWM 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ncthwm
|
||||
.Nd Hardware monitoring controller on Nuvoton Super I/Os
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device ncthwm"
|
||||
.Cd "device superio"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
is a driver for hardware monitoring controller that can be found in Nuvoton
|
||||
Super I/O chips. It expose fan speed via
|
||||
.Xr sysctl 8 .
|
||||
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
driver supports the following chips:
|
||||
.Pp
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
Nuvoton NCT6779
|
||||
.It
|
||||
Nuvoton NCT6796D-E
|
||||
.El
|
||||
|
||||
.Sh SYSCTL VARIABLES
|
||||
These variables are available as read-only
|
||||
.Xr sysctl 8
|
||||
variables:
|
||||
.Bl -tag -width indent
|
||||
.It Va dev.ncthwm.0.CPUFAN
|
||||
CPU fan speed in RPM.
|
||||
.It Va dev.ncthwm.0.SYSFAN
|
||||
System fan speed in RPM.
|
||||
.It Va dev.ncthwm.0.AUXFAN0
|
||||
AUX0 fan speed in RPM.
|
||||
.It Va dev.ncthwm.0.AUXFAN1
|
||||
AUX1 fan speed in RPM.
|
||||
.It Va dev.ncthwm.0.AUXFAN2
|
||||
AUX2 fan speed in RPM.
|
||||
.El
|
||||
|
||||
.Sh HISTORY
|
||||
The driver first appeared in
|
||||
.Fx 14.0 .
|
||||
.Sh AUTHORS
|
||||
The driver was initially written by
|
||||
.An Stéphane Rochoy Aq Mt stephane.rochoy@stormshield.eu .
|
||||
@@ -239,6 +239,7 @@ dev/ixl/i40e_adminq.c optional ixl pci \
|
||||
dev/ixl/i40e_dcb.c optional ixl pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/ixl"
|
||||
dev/nctgpio/nctgpio.c optional nctgpio
|
||||
dev/ncthwm/ncthwm.c optional ncthwm superio
|
||||
dev/nfe/if_nfe.c optional nfe pci
|
||||
dev/ntb/if_ntb/if_ntb.c optional if_ntb
|
||||
dev/ntb/ntb_transport.c optional ntb_transport | if_ntb
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2016-2022 Stormshield
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/watchdog.h>
|
||||
|
||||
#include <dev/superio/superio.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#define NCTHWM_FAN_MAX 5
|
||||
|
||||
#define NCTHWM_BANK_SELECT 0x4e
|
||||
#define NCTHWM_VENDOR_ID 0x4f
|
||||
|
||||
#define NCTHWM_VERBOSE_PRINTF(dev, ...) \
|
||||
do { \
|
||||
if (__predict_false(bootverbose)) \
|
||||
device_printf(dev, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
struct ncthwm_softc {
|
||||
device_t dev;
|
||||
struct ncthwm_device *nctdevp;
|
||||
struct resource *iores;
|
||||
int iorid;
|
||||
};
|
||||
|
||||
struct ncthwm_fan_info
|
||||
{
|
||||
const char *name;
|
||||
uint8_t low_byte_offset;
|
||||
uint8_t high_byte_offset;
|
||||
};
|
||||
|
||||
struct ncthwm_device {
|
||||
uint16_t devid;
|
||||
const char *descr;
|
||||
uint8_t base_offset;
|
||||
uint8_t fan_bank;
|
||||
uint8_t fan_count;
|
||||
struct ncthwm_fan_info fan_info[NCTHWM_FAN_MAX];
|
||||
} ncthwm_devices[] = {
|
||||
{
|
||||
.devid = 0xc562,
|
||||
.descr = "HWM on Nuvoton NCT6779D",
|
||||
.base_offset = 5,
|
||||
.fan_bank = 4,
|
||||
.fan_count = 5,
|
||||
.fan_info = {
|
||||
{ .name = "SYSFAN", .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
|
||||
{ .name = "CPUFAN", .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
|
||||
{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
|
||||
{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
|
||||
{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
|
||||
},
|
||||
}, {
|
||||
.devid = 0xd42a,
|
||||
.descr = "HWM on Nuvoton NCT6796D-E",
|
||||
.base_offset = 5,
|
||||
.fan_bank = 4,
|
||||
.fan_count = 5,
|
||||
.fan_info = {
|
||||
{ .name = "SYSFAN", .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
|
||||
{ .name = "CPUFAN", .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
|
||||
{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
|
||||
{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
|
||||
{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct ncthwm_device *
|
||||
ncthwm_lookup_device(device_t dev)
|
||||
{
|
||||
int i;
|
||||
uint16_t devid;
|
||||
|
||||
devid = superio_devid(dev);
|
||||
for (i = 0; i < nitems(ncthwm_devices); i++) {
|
||||
if (devid == ncthwm_devices[i].devid)
|
||||
return (ncthwm_devices + i);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
ncthwm_write(struct ncthwm_softc *sc, uint8_t reg, uint8_t val)
|
||||
{
|
||||
bus_write_1(sc->iores, 0, reg);
|
||||
bus_write_1(sc->iores, 1, val);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
ncthwm_read(struct ncthwm_softc *sc, uint8_t reg)
|
||||
{
|
||||
bus_write_1(sc->iores, 0, reg);
|
||||
return (bus_read_1(sc->iores, 1));
|
||||
}
|
||||
|
||||
static int
|
||||
ncthwm_query_fan_speed(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct ncthwm_softc *sc;
|
||||
struct ncthwm_fan_info *fan;
|
||||
uint16_t val;
|
||||
|
||||
sc = arg1;
|
||||
if (sc == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
KASSERT(sc->nctdevp != NULL, ("Unreachable"));
|
||||
|
||||
if (sc->nctdevp->fan_count <= arg2)
|
||||
return (EINVAL);
|
||||
fan = &sc->nctdevp->fan_info[arg2];
|
||||
|
||||
KASSERT(sc->iores != NULL, ("Unreachable"));
|
||||
|
||||
ncthwm_write(sc, NCTHWM_BANK_SELECT, sc->nctdevp->fan_bank);
|
||||
val = ncthwm_read(sc, fan->high_byte_offset) << 8;
|
||||
val |= ncthwm_read(sc, fan->low_byte_offset);
|
||||
|
||||
NCTHWM_VERBOSE_PRINTF(sc->dev, "%s: read %u from bank %u offset 0x%x-0x%x\n",
|
||||
fan->name, val, sc->nctdevp->fan_bank, fan->high_byte_offset, fan->low_byte_offset);
|
||||
|
||||
return (sysctl_handle_int(oidp, &val, 0, req));
|
||||
}
|
||||
|
||||
static int
|
||||
ncthwm_probe(device_t dev)
|
||||
{
|
||||
struct ncthwm_device *nctdevp;
|
||||
uint8_t ldn;
|
||||
|
||||
ldn = superio_get_ldn(dev);
|
||||
|
||||
if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) {
|
||||
NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn);
|
||||
return (ENXIO);
|
||||
}
|
||||
if (superio_get_type(dev) != SUPERIO_DEV_HWM) {
|
||||
NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a HWM device\n", ldn);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
nctdevp = ncthwm_lookup_device(dev);
|
||||
if (nctdevp == NULL) {
|
||||
NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn);
|
||||
return (ENXIO);
|
||||
}
|
||||
device_set_desc(dev, nctdevp->descr);
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
ncthwm_attach(device_t dev)
|
||||
{
|
||||
struct ncthwm_softc *sc;
|
||||
int i;
|
||||
uint16_t iobase;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->dev = dev;
|
||||
|
||||
sc->nctdevp = ncthwm_lookup_device(dev);
|
||||
if (sc->nctdevp == NULL) {
|
||||
device_printf(dev, "device not supported\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
iobase = superio_get_iobase(dev) + sc->nctdevp->base_offset;
|
||||
sc->iorid = 0;
|
||||
if (bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid, iobase, 2) != 0) {
|
||||
device_printf(dev, "failed to set I/O port resource at 0x%x\n", iobase);
|
||||
return (ENXIO);
|
||||
}
|
||||
sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
|
||||
&sc->iorid, RF_ACTIVE);
|
||||
if (sc->iores == NULL) {
|
||||
device_printf(dev, "can't map I/O space at 0x%x\n", iobase);
|
||||
return (ENXIO);
|
||||
}
|
||||
NCTHWM_VERBOSE_PRINTF(dev, "iobase 0x%x iores %p\n", iobase, sc->iores);
|
||||
|
||||
/* Register FAN sysctl */
|
||||
for (i = 0; i < sc->nctdevp->fan_count; i++) {
|
||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
|
||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
|
||||
sc->nctdevp->fan_info[i].name,
|
||||
CTLTYPE_U16 | CTLFLAG_RD, sc, i,
|
||||
ncthwm_query_fan_speed, "SU", "Fan speed in RPM");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ncthwm_detach(device_t dev)
|
||||
{
|
||||
struct ncthwm_softc *sc = device_get_softc(dev);
|
||||
|
||||
if (sc->iores)
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t ncthwm_methods[] = {
|
||||
/* Methods from the device interface */
|
||||
DEVMETHOD(device_probe, ncthwm_probe),
|
||||
DEVMETHOD(device_attach, ncthwm_attach),
|
||||
DEVMETHOD(device_detach, ncthwm_detach),
|
||||
|
||||
/* Terminate method list */
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t ncthwm_driver = {
|
||||
"ncthwm",
|
||||
ncthwm_methods,
|
||||
sizeof (struct ncthwm_softc)
|
||||
};
|
||||
|
||||
DRIVER_MODULE(ncthwm, superio, ncthwm_driver, NULL, NULL);
|
||||
MODULE_DEPEND(ncthwm, superio, 1, 1, 1);
|
||||
MODULE_VERSION(ncthwm, 1);
|
||||
@@ -303,6 +303,7 @@ const struct sio_device nct611x_devices[] = {
|
||||
const struct sio_device nct67xx_devices[] = {
|
||||
{ .ldn = 0x8, .type = SUPERIO_DEV_WDT },
|
||||
{ .ldn = 0x9, .type = SUPERIO_DEV_GPIO },
|
||||
{ .ldn = 0xb, .type = SUPERIO_DEV_HWM },
|
||||
{ .type = SUPERIO_DEV_NONE },
|
||||
};
|
||||
|
||||
|
||||
@@ -275,6 +275,7 @@ SUBDIR= \
|
||||
mxge \
|
||||
my \
|
||||
${_nctgpio} \
|
||||
${_ncthwm} \
|
||||
${_neta} \
|
||||
netlink \
|
||||
${_netgraph} \
|
||||
@@ -726,6 +727,7 @@ _lio= lio
|
||||
_mana= mana
|
||||
_mgb= mgb
|
||||
_nctgpio= nctgpio
|
||||
_ncthwm= ncthwm
|
||||
_ntb= ntb
|
||||
_ocs_fc= ocs_fc
|
||||
_p2sb= p2sb
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${SRCTOP}/sys/dev/ncthwm
|
||||
KMOD= ncthwm
|
||||
SRCS= ncthwm.c
|
||||
SRCS+= device_if.h bus_if.h isa_if.h opt_platform.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
Reference in New Issue
Block a user