Mercurial > illumos > git > illumos-joyent
changeset 25205:2afbf6d9e698
12830 Want centralized ksensor framework
12831 temperature sensors could describe accuracy
12832 topo support for generic PCI device temp sensors
Reviewed by: Ryan Zezeski <ryan@zinascii.com>
Reviewed by: Toomas Soome <toomas@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
line wrap: on
line diff
--- a/exception_lists/packaging Thu Jun 25 01:45:50 2020 +0000 +++ b/exception_lists/packaging Sat Apr 04 21:20:18 2020 -0700 @@ -861,12 +861,6 @@ usr/bin/ctfmerge # -# SPARC doesn't currently use this today, though it may in the future. -# -usr/include/sys/sensors.h sparc -usr/lib/devfsadm/linkmod/SUNW_sensor_link.so sparc - -# # libjedec is private # usr/include/libjedec.h
--- a/usr/src/cmd/devfsadm/sensor_link.c Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/cmd/devfsadm/sensor_link.c Sat Apr 04 21:20:18 2020 -0700 @@ -11,6 +11,7 @@ /* * Copyright 2019, Joyent, Inc. + * Copyright 2020 Oxide Computer Company */ /* @@ -33,8 +34,8 @@ static int sensor_link(di_minor_t minor, di_node_t node) { - const char *t, *minor_name, *dir_path = NULL; - char *type, *c; + const char *t, *dir_path = NULL; + char *type, *name, *c; char buf[PATH_MAX]; size_t len; @@ -42,27 +43,40 @@ return (DEVFSADM_CONTINUE); } - if ((minor_name = di_minor_name(minor)) == NULL) { - return (DEVFSADM_CONTINUE); - } - if ((type = strdup(t)) == NULL) { return (DEVFSADM_TERMINATE); } - while ((c = strchr(type, ':')) != NULL) { + c = type; + while ((c = strchr(c, ':')) != NULL) { if (dir_path == NULL) { dir_path = c + 1; } *c = '/'; } + if ((t = di_minor_name(minor)) == NULL) { + free(type); + return (DEVFSADM_CONTINUE); + } + + if ((name = strdup(t)) == NULL) { + free(type); + return (DEVFSADM_TERMINATE); + } + + c = name; + while ((c = strchr(c, ':')) != NULL) { + *c = '/'; + } + + if (dir_path == NULL || *dir_path == '\0') { len = snprintf(buf, sizeof (buf), "%s/%s", SENSORS_BASE, - minor_name); + name); } else { len = snprintf(buf, sizeof (buf), "%s/%s/%s", SENSORS_BASE, - dir_path, minor_name); + dir_path, name); } if (len < sizeof (buf)) { @@ -70,6 +84,7 @@ } free(type); + free(name); return (DEVFSADM_CONTINUE); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/lib/fm/topo/modules/common/pcibus/pci_sensor.c Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,95 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * Construct sensors based on the ksensor framework for PCI devices. The kernel + * will create devices such that they show up + * /dev/sensors/temperature/pci/<bus>.<func>/<sensors>. This iterates and adds a + * sensor for the device based on the total number that exist for all of them. + */ + +#include <sys/types.h> +#include <dirent.h> +#include <string.h> +#include <errno.h> +#include <fm/topo_mod.h> +#include <fm/topo_hc.h> +#include <pcibus.h> +#include <topo_sensor.h> + +int +pci_create_dev_sensors(topo_mod_t *mod, tnode_t *dev) +{ + int ret; + DIR *d; + char path[PATH_MAX]; + topo_instance_t binst, dinst; + struct dirent *ent; + tnode_t *parent = topo_node_parent(dev); + + binst = topo_node_instance(parent); + dinst = topo_node_instance(dev); + + if (snprintf(path, sizeof (path), "/dev/sensors/temperature/pci/%x.%x", + binst, dinst) >= sizeof (path)) { + topo_mod_dprintf(mod, "failed to construct temp sensor " + "directory path, path too long"); + return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); + } + + topo_mod_dprintf(mod, "searching for sensors in %s", path); + + d = opendir(path); + if (d == NULL) { + if (errno == ENOENT) { + return (0); + } + + topo_mod_dprintf(mod, "failed to open %s: %s", path, + strerror(errno)); + return (topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM)); + } + + while ((ent = readdir(d)) != NULL) { + char spath[PATH_MAX]; + + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) { + continue; + } + + if (snprintf(spath, sizeof (spath), "%s/%s", path, + ent->d_name) >= sizeof (spath)) { + topo_mod_dprintf(mod, "failed to construct temp sensor " + "path for %s/%s, path too long", path, ent->d_name); + ret = topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); + goto out; + } + + topo_mod_dprintf(mod, "attempting to create sensor at %s", + spath); + if ((ret = topo_sensor_create_temp_sensor(mod, dev, spath, + ent->d_name)) < 0) { + goto out; + } + + } + ret = 0; + +out: + (void) closedir(d); + + return (ret); +}
--- a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c Sat Apr 04 21:20:18 2020 -0700 @@ -493,6 +493,11 @@ return (NULL); } + if (pci_create_dev_sensors(mod, ntn) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* * We can expect to find pci-express functions beneath the device */ @@ -577,6 +582,11 @@ return (NULL); } + if (pci_create_dev_sensors(mod, ntn) < 0) { + topo_node_unbind(ntn); + return (NULL); + } + /* * We can expect to find pci functions beneath the device */
--- a/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.h Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.h Sat Apr 04 21:20:18 2020 -0700 @@ -27,8 +27,6 @@ #ifndef _PCIBUS_H #define _PCIBUS_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/pci.h> #include <fm/topo_mod.h> #include <libdevinfo.h> @@ -81,6 +79,7 @@ int, int, int, int, int); extern int platform_pci_label(topo_mod_t *, tnode_t *, nvlist_t *, nvlist_t **); +extern int pci_create_dev_sensors(topo_mod_t *, tnode_t *); #ifdef __cplusplus }
--- a/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/lib/fm/topo/modules/i86pc/pcibus/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -31,8 +31,10 @@ HBDIR = ../../common/hostbridge NICDIR = ../../common/nic USBDIR = ../../common/usb +SHAREDDIR = ../../common/shared UTILSRCS = did.c did_hash.c did_props.c util.c -PCISRCS = pcibus.c pcibus_labels.c pcibus_hba.c +PCISRCS = pcibus.c pcibus_labels.c pcibus_hba.c pci_sensor.c +SHAREDSRCS = topo_sensor.c MODULESRCS = $(UTILSRCS) $(PCISRCS) pci_i86pc.c @@ -40,4 +42,8 @@ LDLIBS += -ldevinfo -lsmbios -lpcidb -CPPFLAGS += -I$(UTILDIR) -I$(HBDIR) -I$(NICDIR) -I$(USBDIR) +CPPFLAGS += -I$(UTILDIR) -I$(HBDIR) -I$(NICDIR) -I$(USBDIR) -I$(SHAREDDIR) + +%.o: $(SHAREDDIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O)
--- a/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/lib/fm/topo/modules/sun4/pcibus/Makefile.pci Sat Apr 04 21:20:18 2020 -0700 @@ -31,8 +31,10 @@ NICDIR = ../../common/nic USBDIR = ../../common/usb HBDIR = ../../common/hostbridge +SHAREDDIR = ../../common/shared UTILSRCS = did.c did_hash.c did_props.c util.c -PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c pcibus_hba.c +PCISRCS = pcibus.c pcibus_labels.c pci_sun4.c pcibus_hba.c pci_sensor.c +SHAREDSRCS = topo_sensor.c MODULESRCS = $(PCISRCS) $(UTILSRCS) pci_$(ARCH).c @@ -40,6 +42,7 @@ LDLIBS += -ldevinfo -lsmbios -lpcidb CPPFLAGS += -I$(SUN4DIR) -I$(UTILDIR) -I$(HBDIR) -I$(NICDIR) -I$(USBDIR) +CPPFLAGS += -I$(SHAREDDIR) %.o: $(SUN4DIR)/%.c $(COMPILE.c) -o $@ $< @@ -48,3 +51,7 @@ %.o: $(UTILDIR)/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) + +%.o: $(SHAREDDIR)/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O)
--- a/usr/src/man/man7d/Makefile Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/man/man7d/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -78,6 +78,7 @@ ixgbe.7d \ kmdb.7d \ kstat.7d \ + ksensor.7d \ ksyms.7d \ llc1.7d \ lockstat.7d \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/man/man7d/ksensor.7d Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,41 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright 2020 Oxide Computer Company +.\" +.Dd June 9, 2020 +.Dt KSENSOR 7D +.Os +.Sh NAME +.Nm ksensor +.Nd kernel sensor driver +.Sh SYNOPSIS +.In sys/sensors.h +.Pp +.Pa /dev/sensors/ +.Sh DESCRIPTION +The +.Nm +driver provides access to sensors that are built using the kernel sensor +framework. +Sensors register with the framework are automatically made available to +the system and used with the fault management architecture +.Pq FMA . +.Pp +The file system location and programming interface to the +.Nm +driver are considered +.Sy Volatile , +subject to change without notice, and should not be used directly. +Sensor information can be dumped through the FMA developer utility +.Sy fmtopo . +.Sh SEE ALSO +.Xr fmadm 1M
--- a/usr/src/pkg/manifests/driver-cpu-sensor.mf Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/pkg/manifests/driver-cpu-sensor.mf Sat Apr 04 21:20:18 2020 -0700 @@ -23,10 +23,6 @@ dir path=kernel group=sys dir path=kernel/drv group=sys dir path=kernel/drv/$(ARCH64) group=sys -dir path=usr/include -dir path=usr/include/sys -dir path=usr/lib/devfsadm group=sys -dir path=usr/lib/devfsadm/linkmod group=sys dir path=usr/share/man dir path=usr/share/man/man7d driver name=amdf17nbdf \ @@ -63,10 +59,9 @@ file path=kernel/drv/$(ARCH64)/coretemp group=sys file path=kernel/drv/$(ARCH64)/pchtemp group=sys file path=kernel/drv/coretemp.conf group=sys -file path=usr/include/sys/sensors.h mode=0644 -file path=usr/lib/devfsadm/linkmod/SUNW_sensor_link.so group=sys file path=usr/share/man/man7d/amdf17nbdf.7d file path=usr/share/man/man7d/amdnbtemp.7d file path=usr/share/man/man7d/coretemp.7d file path=usr/share/man/man7d/pchtemp.7d license lic_CDDL license=lic_CDDL +depend fmri=system/ksensor type=require
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/pkg/manifests/system-ksensor.mf Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,36 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +<include global_zone_only_component> +set name=pkg.fmri value=pkg:/system/ksensor@$(PKGVERS) +set name=pkg.description value="Kernel Sensor Framework" +set name=pkg.summary value="Kernel Sensor Framework" +set name=info.classification \ + value=org.opensolaris.category.2008:System/Hardware +dir path=kernel/drv group=sys +dir path=kernel/drv/$(ARCH64) group=sys +dir path=usr/include +dir path=usr/include/sys +dir path=usr/lib/devfsadm group=sys +dir path=usr/lib/devfsadm/linkmod group=sys +dir path=usr/share/man +dir path=usr/share/man/man7d +driver name=ksensor +file path=kernel/drv/$(ARCH64)/ksensor group=sys +file path=kernel/drv/ksensor.conf group=sys +file path=usr/include/sys/sensors.h mode=0644 +file path=usr/lib/devfsadm/linkmod/SUNW_sensor_link.so group=sys +file path=usr/share/man/man7d/ksensor.7d +license lic_CDDL license=lic_CDDL
--- a/usr/src/pkg/manifests/system-test-ostest.mf Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/pkg/manifests/system-test-ostest.mf Sat Apr 04 21:20:18 2020 -0700 @@ -22,6 +22,8 @@ set name=info.classification \ value=org.opensolaris.category.2008:Development/System set name=variant.arch value=$(ARCH) +dir path=kernel/drv group=sys +dir path=kernel/drv/$(ARCH64) group=sys dir path=opt/os-tests dir path=opt/os-tests/bin dir path=opt/os-tests/runfiles @@ -29,6 +31,7 @@ dir path=opt/os-tests/tests/ddi_ufm dir path=opt/os-tests/tests/file-locking $(i386_ONLY)dir path=opt/os-tests/tests/i386 +dir path=opt/os-tests/tests/ksensor dir path=opt/os-tests/tests/libtopo dir path=opt/os-tests/tests/pf_key dir path=opt/os-tests/tests/sdevfs @@ -38,6 +41,8 @@ dir path=opt/os-tests/tests/stress dir path=opt/os-tests/tests/timer dir path=opt/os-tests/tests/uccid +file path=kernel/drv/$(ARCH64)/ksensor_test group=sys +file path=kernel/drv/ksensor_test.conf group=sys file path=opt/os-tests/README mode=0444 file path=opt/os-tests/bin/ostest mode=0555 file path=opt/os-tests/runfiles/default.run mode=0444 @@ -53,6 +58,16 @@ $(i386_ONLY)file path=opt/os-tests/tests/i386/badseg_exec mode=0555 $(i386_ONLY)file path=opt/os-tests/tests/i386/ldt mode=0555 $(i386_ONLY)file path=opt/os-tests/tests/imc_test mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_basic.32 mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_basic.64 mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_err.32 mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_err.64 mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_fini mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_init mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_sread.32 mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_sread.64 mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_stress mode=0555 +file path=opt/os-tests/tests/ksensor/ksensor_unload mode=0555 file path=opt/os-tests/tests/libtopo/digraph-test mode=0555 file path=opt/os-tests/tests/libtopo/digraph-test-in-badedge.xml mode=0444 file path=opt/os-tests/tests/libtopo/digraph-test-in-badelement.xml mode=0444
--- a/usr/src/test/os-tests/runfiles/default.run Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/test/os-tests/runfiles/default.run Sat Apr 04 21:20:18 2020 -0700 @@ -100,3 +100,14 @@ [/opt/os-tests/tests/libtopo] user = root tests = ['digraph-test'] + +# +# Only the ksensor functional tests are included in the run file. +# The stress test is designed to be run separately. +# +[/opt/os-tests/tests/ksensor] +user = root +pre = ksensor_init +tests = [ 'ksensor_basic.32','ksensor_basic.64', 'ksensor_err.32', + 'ksensor_err.64' ] +post = ksensor_fini
--- a/usr/src/test/os-tests/tests/Makefile Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/test/os-tests/tests/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -19,6 +19,7 @@ SUBDIRS = \ ddi_ufm \ file-locking \ + ksensor \ libtopo \ pf_key \ poll \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,71 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +PROGS = \ + ksensor_basic \ + ksensor_err \ + ksensor_sread + +SCRIPTS = \ + ksensor_init \ + ksensor_fini \ + ksensor_stress \ + ksensor_unload + +PROGS32 = $(PROGS:%=%.32) +PROGS64 = $(PROGS:%=%.64) + +ROOTOPTDIR = $(ROOT)/opt/os-tests/tests +ROOTOPTKSENSOR = $(ROOTOPTDIR)/ksensor +ROOTOPTPROGS = $(PROGS32:%=$(ROOTOPTKSENSOR)/%) \ + $(PROGS64:%=$(ROOTOPTKSENSOR)/%) \ + $(SCRIPTS:%=$(ROOTOPTKSENSOR)/%) + +include $(SRC)/cmd/Makefile.cmd + +.KEEP_STATE: + +all: $(PROGS32) $(PROGS64) + +install: $(ROOTOPTPROGS) + +clean: + +$(ROOTOPTPROGS): $(PROGS32) $(PROGS64) $(ROOTOPTKSENSOR) + +$(ROOTOPTDIR): + $(INS.dir) + +$(ROOTOPTKSENSOR): $(ROOTOPTDIR) + $(INS.dir) + +$(ROOTOPTKSENSOR)/%: % + $(INS.file) + +$(ROOTOPTKSENSOR)/%: %.ksh + $(INS.rename) + +%.64: %.c + $(LINK64.c) -o $@ $< $(LDLIBS64) + $(POST_PROCESS) + +%.32: %.c + $(LINK.c) -o $@ $< $(LDLIBS) + $(POST_PROCESS) + +clobber: + $(RM) $(PROGS32) $(PROGS64) + +FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/ksensor_basic.c Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,92 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * Basic ksensor functionality test + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <err.h> +#include <sys/sensors.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +static const char *ksensor_path = "/dev/sensors/test/test.temp.0.1"; + +int +main(void) +{ + sensor_ioctl_kind_t kind; + sensor_ioctl_temperature_t temp; + int ret = 0; + + int fd = open(ksensor_path, O_RDONLY); + if (fd < 0) { + err(EXIT_FAILURE, "TEST FAILED: failed to open %s", + ksensor_path); + } + + arc4random_buf(&kind, sizeof (kind)); + arc4random_buf(&temp, sizeof (temp)); + + if (ioctl(fd, SENSOR_IOCTL_TYPE, &kind) != 0) { + warn("TEST FAILED: failed to get sensor type"); + ret = EXIT_FAILURE; + } + + if (kind.sik_kind != SENSOR_KIND_TEMPERATURE) { + warnx("TEST FAILED: expected temperature sensor, found kind %d", + kind); + ret = EXIT_FAILURE; + } + + if (ioctl(fd, SENSOR_IOCTL_TEMPERATURE, &temp) != 0) { + warn("TEST FAILED: failed to get sensor temperature"); + ret = EXIT_FAILURE; + } + + /* + * These values come from the dummy temperature sensor in ksensor_test. + */ + if (temp.sit_unit != SENSOR_UNIT_CELSIUS) { + warnx("TEST FAILED: expected temp unit %" PRIu32 ", but found " + "%" PRIu32, SENSOR_UNIT_CELSIUS, temp.sit_unit); + ret = EXIT_FAILURE; + } + + if (temp.sit_gran != 4) { + warnx("TEST FAILED: expected temp gran %" PRId32 ", but found " + "%" PRId32, 4, temp.sit_gran); + ret = EXIT_FAILURE; + } + + if (temp.sit_prec != -2) { + warnx("TEST FAILED: expected temp prec %" PRId32 ", but found " + "%" PRId32, -2, temp.sit_prec); + ret = EXIT_FAILURE; + } + + if (temp.sit_temp != 23) { + warnx("TEST FAILED: expected temp %" PRId64 ", but found " + "%" PRId64, 23, temp.sit_temp); + ret = EXIT_FAILURE; + } + + return (ret); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/ksensor_err.c Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,117 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * Describe the purpose of this file. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <err.h> +#include <sys/sensors.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <sys/sysmacros.h> + +static const char *error_sensor = "/dev/sensors/test/test.eio.0"; +static int error_exit; + +static void +error_kind(int fd, int exp) +{ + sensor_ioctl_kind_t kind, alt_kind; + + arc4random_buf(&alt_kind, sizeof (alt_kind)); + (void) memcpy(&kind, &alt_kind, sizeof (alt_kind)); + + if (ioctl(fd, SENSOR_IOCTL_TYPE, &kind) == 0) { + warnx("TEST FAILED: SENSIOR_IOCTL_TYPE succeeded on EIO " + "sensor"); + error_exit = EXIT_FAILURE; + } + + if (errno != exp) { + warnx("TEST FAILED: SENSIOR_IOCTL_TYPE got errno %d, " + "expected %d", errno, exp); + error_exit = EXIT_FAILURE; + } + + if (memcmp(&kind, &alt_kind, sizeof (alt_kind)) != 0) { + warnx("TEST FAILED: SENSIOR_IOCTL_TYPE modified data on error"); + error_exit = EXIT_FAILURE; + } +} + +static void +error_temp(int fd, int exp) +{ + sensor_ioctl_temperature_t temp, alt_temp; + + arc4random_buf(&alt_temp, sizeof (alt_temp)); + (void) memcpy(&temp, &alt_temp, sizeof (alt_temp)); + + if (ioctl(fd, SENSOR_IOCTL_TEMPERATURE, &temp) == 0) { + warnx("TEST FAILED: SENSIOR_IOCTL_TEMPERATURE suceeded on " + "EIO sensor"); + error_exit = EXIT_FAILURE; + } + + if (errno != exp) { + warnx("TEST FAILED: SENSIOR_IOCTL_TEMPERATURE got errno %d, " + "expected %d", errno, EIO); + error_exit = EXIT_FAILURE; + } + + if (memcmp(&temp, &alt_temp, sizeof (alt_temp)) != 0) { + warnx("TEST FAILED: SENSIOR_IOCTL_TEMPERATURE modified " + "data on error"); + error_exit = EXIT_FAILURE; + } +} + +int +main(void) +{ + int i; + int flags[] = { O_RDWR, O_WRONLY, O_RDONLY | O_NDELAY, + O_RDONLY | O_NONBLOCK }; + int fd = open(error_sensor, O_RDONLY); + if (fd < 0) { + err(EXIT_FAILURE, "TEST FAILED: failed to open %s", + error_sensor); + } + + error_kind(fd, EIO); + error_temp(fd, EIO); + (void) close(fd); + + /* + * Check for illegal open combinations. + */ + for (i = 0; i < ARRAY_SIZE(flags); i++) { + fd = open(error_sensor, flags[i]); + if (fd >= 0) { + printf("i is %d\n", i); + warnx("TEST FAILED: opened a sensor with flags 0x%x, " + "but expected failure", flags[i]); + error_exit = EXIT_FAILURE; + } + } + + return (error_exit); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/ksensor_fini.ksh Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,23 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +if ! rem_drv ksensor_test; then + printf "failed to remove ksensor_test driver\n" 2>&1 + exit 1 +fi + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/ksensor_init.ksh Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,23 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +if ! add_drv ksensor_test; then + printf "failed to add ksensor_test driver\n" 2>&1 + exit 1 +fi + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/ksensor_sread.c Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,95 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * Basic program that reads random sensors, mostly ignoring errors. This is in + * support of the stress test program. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <sys/sensors.h> +#include <unistd.h> +#include <string.h> +#include <err.h> +#include <limits.h> +#include <strings.h> + +/* + * Wait for a random amount in 1500 ms, but make sure to wait at least 10ms. + */ +static uint32_t timeout = 1500; +static uint32_t skew = 10; + +int +main(int argc, const char *argv[]) +{ + int nsensors = 0, ninst = 0; + uint32_t ms; + + if (argc != 3) { + errx(EXIT_FAILURE, "missing required args: ninstance, " + "nsensors"); + } + + nsensors = atoi(argv[1]); + ninst = atoi(argv[2]); + if (nsensors <= 0 || ninst <= 0) { + errx(EXIT_FAILURE, "got bad values for some of nesnsors (%u), " + "ninst (%u)", nsensors, ninst); + } + + for (;;) { + int fd; + char buf[PATH_MAX]; + uint32_t sens, inst; + struct timespec ts; + sensor_ioctl_temperature_t temp; + + /* 0s based */ + sens = arc4random_uniform(nsensors); + /* 1s based */ + inst = arc4random_uniform(ninst) + 1; + (void) snprintf(buf, sizeof (buf), + "/dev/sensors/test/test.temp.%u.%u", sens, inst); + + fd = open(buf, O_RDONLY); + if (fd < 0) { + warn("failed to open %s", buf); + goto wait; + } + + bzero(&temp, sizeof (temp)); + if (ioctl(fd, SENSOR_IOCTL_TEMPERATURE, &temp) != 0) { + warn("failed to get sensor temp on %s", buf); + } + + if (temp.sit_unit != SENSOR_UNIT_CELSIUS) { + warnx("data from sensor %s looks off, expected sensor " + "to indicate Celsius, but instead %u", + temp.sit_unit); + } + + (void) close(fd); +wait: + ms = arc4random_uniform(timeout) + skew; + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * (NANOSEC / MILLISEC); + (void) nanosleep(&ts, NULL); + } + return (0); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/ksensor_stress.ksh Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,86 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +# +# This is a stress test that tries to just generate a bunch of ksensor +# activity. It will run launching a number of threads that do different +# activities. The goal here is to try and have the following: +# +# o Things trying to modunload the ksensor_test and ksensor driver +# o things trying to actually use the various sensors from the +# ksensor_test driver +# +# To make sure that everything cleans up when this exits, this script +# wraps itself in a ctrun. The caller needs to ensure that the +# ksensor_test driver is loaded to begin with. It may or may not be part +# of the system when all is said and done. +# + +sensor_base="/dev/sensors/test" + +# +# The number of instances that we expect to exist. +# +sensor_inst=42 +sensor_count=4 + +# +# Tunnables +# +sensor_unloaders=50 +sensor_readers=500 + +if [[ ${@:$#} != "elbereth" ]]; then + exec ctrun -o noorphan ksh $0 "elbereth" +fi + + +if [[ ! -L "$sensor_base/test.temp.0.1" ]]; then + printf "missing ksensor test data, ksensor_temp driver loaded\n" 2>&1 + exit 1 +fi + +cat << EOL +Beginning to run the ksensor stress test. This will launch processes +which will: + + o Attempt to modunload 'ksensor' driver ($sensor_unloaders procs) + o Attempt to modunload 'ksensor_test' driver ($sensor_unloaders procs) + o Attempt to read test sensors ($sensor_readers procs) + +To stop things, simply kill this process. All dependent processes will +be cleaned up. +EOL + +for ((i = 0; i < $sensor_unloaders; i++)); do + ksh ./ksensor_unload.ksh ksensor_test & + ksh ./ksensor_unload.ksh ksensor & +done + +for ((i = 0; i < $sensor_readers; i++)); do + if [[ $(( $i % 2 )) -eq 0 ]]; then + ./ksensor_sread.32 $sensor_inst $sensor_count & + else + ./ksensor_sread.64 $sensor_inst $sensor_count & + fi +done + +while :; do + wait +done + +exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/test/os-tests/tests/ksensor/ksensor_unload.ksh Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,59 @@ +#!/usr/bin/ksh +# +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +# +# Sit in a loop trying to unload the driver specified as an argument. +# + +ksensor_id= +ksensor_drv= +ksensor_to=30 +ksensor_skew=5 + +function get_id +{ + + while [[ -z "$ksensor_id" ]]; do + sleep 1 + ksensor_id=$(modinfo | awk "{ + if (\$6 == \"$1\") { + print \$1 + } }") + done +} + +function unload +{ + while :; do + if ! modunload -i $ksensor_id 2>/dev/null; then + echo "failed to unload $ksensor_drv" >&2 + else + echo "unloaded $ksensor_drv" + fi + sleep $((($RANDOM % $ksensor_to) + $ksensor_skew)) + done +} + +if [[ -z "$1" ]]; then + echo "Missing required driver name" >&2 + exit 1 +fi + +ksensor_drv=$1 +get_id $ksensor_drv +printf "Got module id for %s: %u\n" "$ksensor_drv" $ksensor_id +unload
--- a/usr/src/uts/common/Makefile.files Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/Makefile.files Sat Apr 04 21:20:18 2020 -0700 @@ -217,6 +217,7 @@ kiconv.o \ klpd.o \ kmem.o \ + ksensor.o \ ksyms_snapshot.o \ l_strplumb.o \ labelsys.o \ @@ -743,6 +744,9 @@ KSTAT_OBJS += kstat.o +KSENSOR_OBJS += ksensor_drv.o +KSENSOR_TEST_OBJS += ksensor_test.o + KSYMS_OBJS += ksyms.o INSTANCE_OBJS += inst_sync.o
--- a/usr/src/uts/common/Makefile.rules Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/Makefile.rules Sat Apr 04 21:20:18 2020 -0700 @@ -913,6 +913,10 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/ksensor/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/io/ksocket/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/ksensor/ksensor.conf Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,23 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +name="ksensor" parent="pseudo" instance=0; + +# +# Unfortunately, to support the fact that drivers can come and create +# sensors at any time. Right now the kernel doesn't cons the ksensor +# driver back into existence. +# +ddi-forceattach=1;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/ksensor/ksensor_drv.c Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,275 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * This pseudo-device driver implements access to kernel sensors. See + * uts/common/os/ksensor.c for more information on the framework and how this + * driver fits in. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/open.h> +#include <sys/cred.h> +#include <sys/stat.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/modctl.h> +#include <sys/conf.h> +#include <sys/devops.h> +#include <sys/zone.h> +#include <sys/ksensor_impl.h> + +static dev_info_t *ksensor_dip; + +static int +ksensor_create_cb(id_t id, const char *class, const char *name) +{ + if (ddi_create_minor_node(ksensor_dip, name, S_IFCHR, (minor_t)id, + class, 0) != 0) { + dev_err(ksensor_dip, CE_WARN, "!failed to create ksensor node " + "for %s:%s (minor %d)", class, name, id); + return (EIO); + } + + return (0); +} + +static void +ksensor_remove_cb(id_t id, const char *name) +{ + ddi_remove_minor_node(ksensor_dip, (char *)name); +} + +static int +ksensor_open(dev_t *devp, int flags, int otype, cred_t *credp) +{ + if (crgetzoneid(credp) != GLOBAL_ZONEID || drv_priv(credp) != 0) { + return (EPERM); + } + + if ((flags & (FEXCL | FNDELAY | FNONBLOCK | FWRITE)) != 0) { + return (EINVAL); + } + + if (otype != OTYP_CHR) { + return (EINVAL); + } + + return (0); +} + +static int +ksensor_ioctl_kind(minor_t min, intptr_t arg, int mode) +{ + int ret; + sensor_ioctl_kind_t kind; + + bzero(&kind, sizeof (kind)); + ret = ksensor_op_kind((id_t)min, &kind); + if (ret == 0) { + if (ddi_copyout(&kind, (void *)arg, sizeof (kind), + mode & FKIOCTL) != 0) { + ret = EFAULT; + } + } + return (ret); +} + +static int +ksensor_ioctl_temp(minor_t min, intptr_t arg, int mode) +{ + int ret; + sensor_ioctl_temperature_t temp; + + bzero(&temp, sizeof (temp)); + ret = ksensor_op_temperature((id_t)min, &temp); + if (ret == 0) { + if (ddi_copyout(&temp, (void *)arg, sizeof (temp), + mode & FKIOCTL) != 0) { + ret = EFAULT; + } + } + return (ret); +} + +static int +ksensor_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, + int *rvalp) +{ + minor_t m; + + if ((mode & FREAD) == 0) { + return (EINVAL); + } + + m = getminor(dev); + switch (cmd) { + case SENSOR_IOCTL_TYPE: + return (ksensor_ioctl_kind(m, arg, mode)); + case SENSOR_IOCTL_TEMPERATURE: + return (ksensor_ioctl_temp(m, arg, mode)); + default: + return (ENOTTY); + } +} + +static int +ksensor_close(dev_t dev, int flags, int otype, cred_t *credp) +{ + return (0); +} + +static int +ksensor_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + switch (cmd) { + case DDI_RESUME: + return (DDI_SUCCESS); + case DDI_ATTACH: + break; + default: + return (DDI_FAILURE); + } + + if (ksensor_dip != NULL) { + dev_err(dip, CE_WARN, "ksensor driver already attatched"); + return (DDI_FAILURE); + } + + ksensor_dip = dip; + if (ksensor_register(dip, ksensor_create_cb, ksensor_remove_cb) != 0) { + ksensor_dip = NULL; + return (DDI_FAILURE); + } + + return (DDI_SUCCESS); +} + +/* + * All minors always maps to a single instance. Don't worry about minor validity + * here. + */ +static int +ksensor_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, + void **resultp) +{ + if (cmd != DDI_INFO_DEVT2DEVINFO && cmd != DDI_INFO_DEVT2INSTANCE) { + return (DDI_FAILURE); + } + + if (cmd == DDI_INFO_DEVT2DEVINFO) { + *resultp = ksensor_dip; + } else { + int inst = ddi_get_instance(ksensor_dip); + *resultp = (void *)(uintptr_t)inst; + } + + return (DDI_SUCCESS); +} + +static int +ksensor_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + switch (cmd) { + case DDI_DETACH: + break; + case DDI_SUSPEND: + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } + + if (ksensor_dip == NULL) { + dev_err(dip, CE_WARN, "asked to detach ksensor driver when no " + "dip is attached"); + return (DDI_FAILURE); + } + + if (ksensor_dip != dip) { + dev_err(dip, CE_WARN, "asked to detach ksensor driver, but dip " + "doesn't match"); + return (DDI_FAILURE); + } + + ksensor_unregister(dip); + ddi_remove_minor_node(dip, NULL); + ksensor_dip = NULL; + return (DDI_SUCCESS); +} + +static struct cb_ops ksensor_cb_ops = { + .cb_open = ksensor_open, + .cb_close = ksensor_close, + .cb_strategy = nodev, + .cb_print = nodev, + .cb_dump = nodev, + .cb_read = nodev, + .cb_write = nodev, + .cb_ioctl = ksensor_ioctl, + .cb_devmap = nodev, + .cb_mmap = nodev, + .cb_segmap = nodev, + .cb_chpoll = nochpoll, + .cb_prop_op = ddi_prop_op, + .cb_flag = D_MP, + .cb_rev = CB_REV, + .cb_aread = nodev, + .cb_awrite = nodev +}; + +static struct dev_ops ksensor_dev_ops = { + .devo_rev = DEVO_REV, + .devo_refcnt = 0, + .devo_getinfo = ksensor_getinfo, + .devo_identify = nulldev, + .devo_probe = nulldev, + .devo_attach = ksensor_attach, + .devo_detach = ksensor_detach, + .devo_reset = nodev, + .devo_power = ddi_power, + .devo_quiesce = ddi_quiesce_not_needed, + .devo_cb_ops = &ksensor_cb_ops +}; + +static struct modldrv ksensor_modldrv = { + .drv_modops = &mod_driverops, + .drv_linkinfo = "Kernel Sensor driver", + .drv_dev_ops = &ksensor_dev_ops +}; + +static struct modlinkage ksensor_modlinkage = { + .ml_rev = MODREV_1, + .ml_linkage = { &ksensor_modldrv, NULL } +}; + +int +_init(void) +{ + return (mod_install(&ksensor_modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&ksensor_modlinkage, modinfop)); +} + +int +_fini(void) +{ + return (mod_remove(&ksensor_modlinkage)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/ksensor/ksensor_test.c Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,217 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * This driver is used to implement parts of the ksensor test suite. + */ + +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/modctl.h> +#include <sys/conf.h> +#include <sys/devops.h> +#include <sys/zone.h> +#include <sys/sensors.h> + +typedef struct ksensor_test { + dev_info_t *kt_dip; + id_t kt_sensor1; + id_t kt_sensor2; + id_t kt_sensor3; + id_t kt_sensor4; + id_t kt_sensor5; +} ksensor_test_t; + +static int +ksensor_test_temperature(void *arg, sensor_ioctl_temperature_t *temp) +{ + temp->sit_unit = SENSOR_UNIT_CELSIUS; + temp->sit_gran = 4; + temp->sit_prec = -2; + temp->sit_temp = 23; + return (0); +} + +static const ksensor_ops_t ksensor_test_temp_ops = { + ksensor_kind_temperature, + ksensor_test_temperature +}; + +static int +ksensor_test_kind_eio(void *arg, sensor_ioctl_kind_t *kindp) +{ + return (EIO); +} + +static int +ksensor_test_temp_eio(void *arg, sensor_ioctl_temperature_t *tempp) +{ + return (EIO); +} + +static const ksensor_ops_t ksensor_test_eio_ops = { + ksensor_test_kind_eio, + ksensor_test_temp_eio +}; + +static int +ksensor_test_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) +{ + int ret; + char buf[128]; + ksensor_test_t *kt; + + switch (cmd) { + case DDI_RESUME: + return (DDI_SUCCESS); + case DDI_ATTACH: + break; + default: + return (DDI_FAILURE); + } + + kt = kmem_zalloc(sizeof (ksensor_test_t), KM_SLEEP); + kt->kt_dip = dip; + + (void) snprintf(buf, sizeof (buf), "test.temp.%d.1", + ddi_get_instance(dip)); + if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf, + "ddi_sensor:test", &kt->kt_sensor1)) != 0) { + dev_err(dip, CE_WARN, "failed to attatch sensor %s: %d", buf, + ret); + goto err; + } + + (void) snprintf(buf, sizeof (buf), "test.temp.%d.2", + ddi_get_instance(dip)); + if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf, + "ddi_sensor:test", &kt->kt_sensor2)) != 0) { + dev_err(dip, CE_WARN, "failed to attatch sensor %s: %d", buf, + ret); + goto err; + } + + (void) snprintf(buf, sizeof (buf), "test.temp.%d.3", + ddi_get_instance(dip)); + if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf, + "ddi_sensor:test", &kt->kt_sensor3)) != 0) { + dev_err(dip, CE_WARN, "failed to attatch sensor %s: %d", buf, + ret); + goto err; + } + + (void) snprintf(buf, sizeof (buf), "test.temp.%d.4", + ddi_get_instance(dip)); + if ((ret = ksensor_create(dip, &ksensor_test_temp_ops, NULL, buf, + "ddi_sensor:test", &kt->kt_sensor4)) != 0) { + dev_err(dip, CE_WARN, "failed to attatch sensor %s: %d", buf, + ret); + goto err; + } + + (void) snprintf(buf, sizeof (buf), "test.eio.%d", + ddi_get_instance(dip)); + if ((ret = ksensor_create(dip, &ksensor_test_eio_ops, NULL, buf, + "ddi_sensor:test", &kt->kt_sensor5)) != 0) { + dev_err(dip, CE_WARN, "failed to attatch sensor %s: %d", buf, + ret); + goto err; + } + + ddi_set_driver_private(dip, kt); + + return (DDI_SUCCESS); +err: + (void) ksensor_remove(dip, KSENSOR_ALL_IDS); + kmem_free(kt, sizeof (ksensor_test_t)); + return (DDI_FAILURE); +} + +static int +ksensor_test_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) +{ + ksensor_test_t *kt; + + switch (cmd) { + case DDI_DETACH: + break; + case DDI_SUSPEND: + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } + + kt = ddi_get_driver_private(dip); + if (kt == NULL) { + dev_err(dip, CE_WARN, "failed to find ksensor_test_t"); + return (DDI_FAILURE); + } + + if (kt->kt_sensor3 != 0 && + ksensor_remove(dip, kt->kt_sensor3) != 0) { + dev_err(dip, CE_WARN, "failed to remove sensor 3"); + return (DDI_FAILURE); + } + kt->kt_sensor3 = 0; + if (ksensor_remove(dip, KSENSOR_ALL_IDS) != 0) { + dev_err(dip, CE_WARN, "failed to remove sensors"); + return (DDI_FAILURE); + } + kmem_free(kt, sizeof (*kt)); + ddi_set_driver_private(dip, NULL); + return (DDI_SUCCESS); +} + +static struct dev_ops ksensor_test_dev_ops = { + .devo_rev = DEVO_REV, + .devo_refcnt = 0, + .devo_getinfo = nodev, + .devo_identify = nulldev, + .devo_probe = nulldev, + .devo_attach = ksensor_test_attach, + .devo_detach = ksensor_test_detach, + .devo_reset = nodev, + .devo_power = ddi_power, + .devo_quiesce = ddi_quiesce_not_needed, +}; + +static struct modldrv ksensor_test_modldrv = { + .drv_modops = &mod_driverops, + .drv_linkinfo = "Kernel Sensor test driver", + .drv_dev_ops = &ksensor_test_dev_ops +}; + +static struct modlinkage ksensor_test_modlinkage = { + .ml_rev = MODREV_1, + .ml_linkage = { &ksensor_test_modldrv, NULL } +}; + +int +_init(void) +{ + return (mod_install(&ksensor_test_modlinkage)); +} + +int +_info(struct modinfo *modinfop) +{ + return (mod_info(&ksensor_test_modlinkage, modinfop)); +} + +int +_fini(void) +{ + return (mod_remove(&ksensor_test_modlinkage)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/io/ksensor/ksensor_test.conf Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,58 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +name="ksensor_test" parent="pseudo" instance=0; +name="ksensor_test" parent="pseudo" instance=1; +name="ksensor_test" parent="pseudo" instance=2; +name="ksensor_test" parent="pseudo" instance=3; +name="ksensor_test" parent="pseudo" instance=4; +name="ksensor_test" parent="pseudo" instance=5; +name="ksensor_test" parent="pseudo" instance=6; +name="ksensor_test" parent="pseudo" instance=7; +name="ksensor_test" parent="pseudo" instance=8; +name="ksensor_test" parent="pseudo" instance=9; +name="ksensor_test" parent="pseudo" instance=10; +name="ksensor_test" parent="pseudo" instance=11; +name="ksensor_test" parent="pseudo" instance=12; +name="ksensor_test" parent="pseudo" instance=13; +name="ksensor_test" parent="pseudo" instance=14; +name="ksensor_test" parent="pseudo" instance=15; +name="ksensor_test" parent="pseudo" instance=16; +name="ksensor_test" parent="pseudo" instance=17; +name="ksensor_test" parent="pseudo" instance=18; +name="ksensor_test" parent="pseudo" instance=19; +name="ksensor_test" parent="pseudo" instance=20; +name="ksensor_test" parent="pseudo" instance=21; +name="ksensor_test" parent="pseudo" instance=22; +name="ksensor_test" parent="pseudo" instance=23; +name="ksensor_test" parent="pseudo" instance=24; +name="ksensor_test" parent="pseudo" instance=25; +name="ksensor_test" parent="pseudo" instance=26; +name="ksensor_test" parent="pseudo" instance=27; +name="ksensor_test" parent="pseudo" instance=28; +name="ksensor_test" parent="pseudo" instance=29; +name="ksensor_test" parent="pseudo" instance=30; +name="ksensor_test" parent="pseudo" instance=31; +name="ksensor_test" parent="pseudo" instance=32; +name="ksensor_test" parent="pseudo" instance=33; +name="ksensor_test" parent="pseudo" instance=34; +name="ksensor_test" parent="pseudo" instance=35; +name="ksensor_test" parent="pseudo" instance=36; +name="ksensor_test" parent="pseudo" instance=37; +name="ksensor_test" parent="pseudo" instance=38; +name="ksensor_test" parent="pseudo" instance=39; +name="ksensor_test" parent="pseudo" instance=40; +name="ksensor_test" parent="pseudo" instance=41; +name="ksensor_test" parent="pseudo" instance=42;
--- a/usr/src/uts/common/mapfiles/ddi.mapfile Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/mapfiles/ddi.mapfile Sat Apr 04 21:20:18 2020 -0700 @@ -70,6 +70,7 @@ cv_reltimedwait { FLAGS = EXTERN }; ddi_cb_register { FLAGS = EXTERN }; ddi_cb_unregister { FLAGS = EXTERN }; + ddi_create_minor_node { FLAGS = EXTERN }; ddi_dev_regsize { FLAGS = EXTERN }; ddi_dma_addr_bind_handle { FLAGS = EXTERN }; ddi_dma_alloc_handle { FLAGS = EXTERN };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/mapfiles/ksensor.mapfile Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,43 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object scoping must comply with the rules detailed in +# +# usr/src/uts/common/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +# +# This file contains functions that are provided for ksensors. +# + +$mapfile_version 2 + +SYMBOL_SCOPE { + global: + ksensor_create { FLAGS = EXTERN }; + ksensor_create_temp_pcidev { FLAGS = EXTERN }; + ksensor_remove { FLAGS = EXTERN }; + ksensor_kind_temperature { FLAGS = EXTERN }; +}; +
--- a/usr/src/uts/common/os/autoconf.c Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/os/autoconf.c Sat Apr 04 21:20:18 2020 -0700 @@ -53,6 +53,7 @@ #include <sys/fm/util.h> #include <sys/ddifm_impl.h> #include <sys/ddi_ufm_impl.h> +#include <sys/ksensor_impl.h> extern dev_info_t *top_devinfo; extern dev_info_t *scsi_vhci_dip; @@ -96,6 +97,7 @@ ndi_fm_init(); irm_init(); ufm_init(); + ksensor_init(); (void) i_ddi_load_drvconf(DDI_MAJOR_T_NONE);
--- a/usr/src/uts/common/os/devcfg.c Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/os/devcfg.c Sat Apr 04 21:20:18 2020 -0700 @@ -397,6 +397,9 @@ devi->devi_ct_count = -1; /* counter not in use if -1 */ list_create(&(devi->devi_ct), sizeof (cont_device_t), offsetof(cont_device_t, cond_next)); + list_create(&devi->devi_unbind_cbs, sizeof (ddi_unbind_callback_t), + offsetof(ddi_unbind_callback_t, ddiub_next)); + mutex_init(&devi->devi_unbind_lock, NULL, MUTEX_DEFAULT, NULL); i_ddi_set_node_state((dev_info_t *)devi, DS_PROTO); da_log_enter((dev_info_t *)devi); @@ -493,6 +496,9 @@ if (devi->devi_ev_path) kmem_free(devi->devi_ev_path, MAXPATHLEN); + mutex_destroy(&devi->devi_unbind_lock); + list_destroy(&devi->devi_unbind_cbs); + kmem_cache_free(ddi_node_cache, devi); } @@ -830,6 +836,7 @@ static int unbind_node(dev_info_t *dip) { + ddi_unbind_callback_t *cb; ASSERT(DEVI(dip)->devi_node_state == DS_BOUND); ASSERT(DEVI(dip)->devi_major != DDI_MAJOR_T_NONE); @@ -844,6 +851,11 @@ DEVI(dip)->devi_major = DDI_MAJOR_T_NONE; DEVI(dip)->devi_binding_name = DEVI(dip)->devi_node_name; + + while ((cb = list_remove_head(&DEVI(dip)->devi_unbind_cbs)) != NULL) { + cb->ddiub_cb(cb->ddiub_arg, dip); + } + return (DDI_SUCCESS); } @@ -9281,3 +9293,13 @@ ; #endif } + +void +e_ddi_register_unbind_callback(dev_info_t *dip, ddi_unbind_callback_t *cb) +{ + struct dev_info *devi = DEVI(dip); + + mutex_enter(&devi->devi_unbind_lock); + list_insert_tail(&devi->devi_unbind_cbs, cb); + mutex_exit(&devi->devi_unbind_lock); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/os/ksensor.c Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,843 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +/* + * Kernel Sensor Framework + * + * The kernel sensor framework exists to provide a simple and straightforward + * means for various parts of the system to declare and instantiate sensor + * information. Between this and the ksensor character device + * (uts/common/io/ksensor/ksensor_drv.c) this exposes per-device sensors and + * character devices. + * + * -------------------------- + * Driver and User Interfaces + * -------------------------- + * + * Each sensor that is registered with the framework is exposed as a character + * device under /dev/sensors. The device class and node name are often ':' + * delineated and must begin with 'ddi_sensor'. Everything after 'ddi_sensor' + * will be created in a directory under /dev/sensors. So for example the Intel + * PCH driver uses a class "ddi_sensor:temperature:pch" and a node name of + * 'ts.%d'. This creates the node /dev/sensors/temperature/pch/ts.0. The + * devfsadm plugin automatically handles the creation of directories which makes + * the addition of additional sensor types easy to create. + * + * Strictly speaking, any device can manage their own sensors and minor nodes by + * using the appropriate class and implementing the corresponding ioctls. That + * was how the first kernel sensors were written; however, there are a lot of + * issues with that which led to this: + * + * 1. Every driver had to actually implement character devices. + * + * 2. Every driver had to duplicate a lot of the logic around open(9E), + * close(9E), and ioctl(9E). + * + * 3. Drivers that tied into frameworks like mac(9E) or SCSAv3 needed a lot more + * work to fit into this model. For example, because the minor state is + * shared between all the instances and the frameworks, they would have + * required shared, global state that they don't have today. + * + * Ultimately, having an operations vector and a callback argument makes work a + * lot simpler for the producers of sensor data and that simplicity makes it + * worthwhile to take on additional effort and work here. + * + * ---------- + * Components + * ---------- + * + * The ksensor framework is made of a couple of different pieces: + * + * 1. This glue that is a part of genunix. + * 2. The ksensor character device driver. + * 3. Sensor providers, which are generally drivers that register with the + * ksensor framework. + * + * The implementation of (1) is all in this file. The implementation of (2) is + * in uts/common/io/ksensor/ksensor_drv.c. The implementation of (3) is found in + * all of the different leaf devices. Examples of (3) include pchtemp(7D) and + * igb(7D). + * + * We separate numbers one and two into two different components for a few + * reasons. The most important thing is that drivers that provide sensors should + * not be dependent on some other part of the system having been loaded. This + * makes a compelling argument for it being a part of the core kernel. However, + * like other subsystems (e.g. kstats, smbios, etc.), it's useful to separate + * out the thing that provides the interface to users with the thing that is + * used to glue together providers in the kernel. There's the added benefit that + * it's practically simpler to spin up a pseudo-device through a module. + * + * The ksensor character device driver (2) registers with the main genunix + * ksensor code (1) when it attaches and when it detaches. The kernel only + * allows a single driver to be attached to it. When that character device + * driver attaches, the ksensor framework will walk through all of the currently + * registered sensors and inform the character device driver of the nodes that + * it needs to create. While the character device driver is attached, the + * ksensor framework will also call back into it when a sensor needs to be + * removed. + * + * Generally speaking, this distinction of responsibilities allows the kernel + * sensor character device driver to attach and detach without impact to the + * sensor providers or them even being notified at all, it's all transparent to + * them. + * + * ------------------------------ + * Sensor Lifetime and detach(9E) + * ------------------------------ + * + * Traditionally, a device driver may be detached by the broader kernel whenever + * the kernel desires it. On debug builds this happens by a dedicated thread. On + * a non-debug build this may happen due to memory pressure or as an attempt to + * reclaim idle resources (though this is much less common). However, when the + * module is detached, the system remembers that minor nodes previously existed + * and that entries in /devices had been created. When something proceeds to + * access an entry in /devices again, the system will use that to bring a driver + * back to life. It doesn't matter whether it's a pseudo-device driver or + * something else, this can happen. + * + * One downside to the sensor framework, is that we need to emulate this + * behavior which leads to some amount of complexity here. But this is a + * worthwhile tradeoff as it makes things much simpler for providers and it's + * not too hard for us to emulate this behavior. + * + * When a sensor provider registers the sensor, the sensor becomes available to + * the system. When the sensor provider unregisters with the system, which + * happens during its detach routine, then we note that it has been detached; + * however, we don't delete its minor node and if something accesses it, we + * attempt to load the driver again, the same way that devfs (the file system + * behind /devices) does. + * + * For each dev_info_t that registers a sensor we register a callback such that + * when the device is removed, e.g. someone called rem_drv or physically pulls + * the device, then we'll be able to finally clean up the device. This lifetime + * can be represented in the following image: + * + * | + * | + * +-----<-------------------------------------+ + * | | + * | . . call ksensor_create() | + * v | + * +-------+ | + * | Valid | | + * +-------+ | + * | ^ + * | . . call ksensor_remove() | + * v | + * +---------+ | + * | Invalid | | + * +---------+ | + * | | | + * | | . . user uses sensor again | + * | | | + * | +-------------------+ | + * | | | + * | v | + * | +---------------+ | + * | | Attatching... |-->---------+ + * | +---------------+ + * | . . ddi unbind cb | + * | | + * v | . . attatch fails or + * +---------+ | no call to ksensor_create() + * | Deleted |--<---------------+ again + * +---------+ + * + * When the DDI unbind callback is called, we know that the device is going to + * be removed. However, this happens within a subtle context with a majority of + * the device tree held (at least the dip's parent). In particular, another + * thread may be trying to obtain a hold on it and be blocked in + * ndi_devi_enter(). As the callback thread holds that, that could lead to a + * deadlock. As a result, we clean things up in two phases. One during the + * synchronous callback and the other via a taskq. In the first phase we + * logically do the following: + * + * o Remove the dip from the list of ksensor dips and set the flag that + * indicates that it's been removed. + * o Remove all of the sensors from the global avl to make sure that new + * threads cannot look it up. + * + * Then, after the taskq is dispatched, we do the following in taskq context: + * + * o Tell the ksensor driver that it should remove the minor node. + * o Block on each sensor until it is no-longer busy and then clean it up. + * o Clean up the ksensor_dip_t. + * + * ------------------ + * Accessing a Sensor + * ------------------ + * + * Access to a particular sensor is serialized in the system. In addition to + * that, a number of steps are required to access one that is not unlike + * accessing a character device. When a given sensor is held the KSENSOR_F_BUSY + * flag is set in the ksensor_flags member. In addition, as part of taking a + * hold a number of side effects occur that ensure that the sensor provider's + * dev_info_t is considered busy and can't be detached. + * + * To obtain a hold on a sensor the following logical steps are required (see + * ksensor_hold_by_id() for the implementation): + * + * 1. Map the minor to the ksensor_t via the avl tree + * 2. Check that the ksensor's dip is valid + * 3. If the sensor is busy, wait until it is no longer so, and restart from + * the top. Otherwise, mark the sensor as busy. + * 4. Enter the parent and place a hold on the sensor provider's dip. + * 5. Once again check if the dip is removed or not because we have to drop + * locks during that operation. + * 6. Check if the ksensor has the valid flag set. If not, attempt to configure + * the dip. + * 7. Assuming the sensor is now valid, we can return it. + * + * After this point, the sensor is considered valid for use. Once the consumer + * is finished with the sensor, it should be released by calling + * ksensor_release(). + * + * An important aspect of the above scheme is that the KSENSOR_F_BUSY flag is + * required to progress through the validation and holding of the device. This + * makes sure that only one thread is attempting to attach it at a given time. A + * reasonable future optimization would be to amortize this cost in open(9E) + * and close(9E) of the minor and to bump a count as it being referenced as long + * as it is open. + * + * ----------------------------- + * Character Device Registration + * ----------------------------- + * + * The 'ksensor' character device driver can come and go. To support this, the + * ksensor framework communicates with the ksensor character device by a + * well-defined set of callbacks, used to indicate sensor addition and removal. + * The ksensor character device is found in uts/common/io/ksensor/ksensor_drv.c. + * The ksensor character device is responsible for creating and destroying minor + * nodes. + * + * Each ksensor_t has a flag, KSENSOR_F_NOTIFIED, that is used to indicate + * whether or not the registered driver has been notified of the sensor. When a + * callback is first registered, we'll walk through the entire list of nodes to + * make sure that its minor has been created. When unregistering, the minor node + * remove callback will not be called; however, this can generally by dealt with + * by calling something like ddi_remove_minor_node(dip, NULL). + * + * ------- + * Locking + * ------- + * + * The following rules apply to dealing with lock ordering: + * + * 1. The global ksensor_g_mutex protects all global data and must be taken + * before a ksensor_t's individual mutex. + * + * 2. A thread should not hold any two ksensor_t's mutex at any time. + * + * 3. No locks should be held when attempting to grab or manipulate a + * dev_info_t, e.g. ndi_devi_enter(). + * + * 4. Unless the ksensor is actively being held, whenever a ksensor is found, + * one must check whether the ksensor_dip_t flag KSENSOR_DIP_F_REMOVED is + * set or not and whether the ksensor_t's KSENSOR_F_VALID flag is set. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/errno.h> +#include <sys/cred.h> +#include <sys/ddi.h> +#include <sys/stat.h> +#include <sys/sunddi.h> +#include <sys/sunndi.h> +#include <sys/esunddi.h> +#include <sys/ksensor_impl.h> +#include <sys/ddi_impldefs.h> +#include <sys/pci.h> +#include <sys/avl.h> +#include <sys/list.h> +#include <sys/stddef.h> +#include <sys/sysmacros.h> +#include <sys/fs/dv_node.h> + +typedef enum { + /* + * This flag indicates that the subscribing ksensor character device has + * been notified about this flag. + */ + KSENSOR_F_NOTIFIED = 1 << 0, + /* + * This indicates that the sensor is currently valid, meaning that the + * ops vector and argument are safe to use. This is removed when a + * driver with a sensor is detached. + */ + KSENSOR_F_VALID = 1 << 1, + /* + * Indicates that a client has a hold on the sensor for some purpose. + * This must be set before trying to get an NDI hold. Once this is set + * and a NDI hold is in place, it is safe to use the operations vector + * and argument. + */ + KSENSOR_F_BUSY = 1 << 2, +} ksensor_flags_t; + +typedef enum { + KSENSOR_DIP_F_REMOVED = 1 << 0 +} ksensor_dip_flags_t; + +typedef struct { + list_node_t ksdip_link; + ksensor_dip_flags_t ksdip_flags; + dev_info_t *ksdip_dip; + ddi_unbind_callback_t ksdip_cb; + list_t ksdip_sensors; +} ksensor_dip_t; + +typedef struct { + kmutex_t ksensor_mutex; + kcondvar_t ksensor_cv; + ksensor_flags_t ksensor_flags; + list_node_t ksensor_dip_list; + avl_node_t ksensor_id_avl; + uint_t ksensor_nwaiters; + ksensor_dip_t *ksensor_ksdip; + char *ksensor_name; + char *ksensor_class; + id_t ksensor_id; + const ksensor_ops_t *ksensor_ops; + void *ksensor_arg; +} ksensor_t; + +static kmutex_t ksensor_g_mutex; +static id_space_t *ksensor_ids; +static list_t ksensor_dips; +static avl_tree_t ksensor_avl; +static dev_info_t *ksensor_cb_dip; +static ksensor_create_f ksensor_cb_create; +static ksensor_remove_f ksensor_cb_remove; + +static int +ksensor_avl_compare(const void *l, const void *r) +{ + const ksensor_t *kl = l; + const ksensor_t *kr = r; + + if (kl->ksensor_id > kr->ksensor_id) { + return (1); + } else if (kl->ksensor_id < kr->ksensor_id) { + return (-1); + } else { + return (0); + } +} + +static ksensor_t * +ksensor_find_by_id(id_t id) +{ + ksensor_t k, *ret; + + ASSERT(MUTEX_HELD(&ksensor_g_mutex)); + + k.ksensor_id = id; + return (avl_find(&ksensor_avl, &k, NULL)); + +} + +static ksensor_t * +ksensor_search_ksdip(ksensor_dip_t *ksdip, const char *name, const char *class) +{ + ksensor_t *s; + + ASSERT(MUTEX_HELD(&ksensor_g_mutex)); + + for (s = list_head(&ksdip->ksdip_sensors); s != NULL; + s = list_next(&ksdip->ksdip_sensors, s)) { + if (strcmp(s->ksensor_name, name) == 0 && + strcmp(s->ksensor_class, class) == 0) { + return (s); + } + } + + return (NULL); +} + +static void +ksensor_free_sensor(ksensor_t *sensor) +{ + strfree(sensor->ksensor_name); + strfree(sensor->ksensor_class); + id_free(ksensor_ids, sensor->ksensor_id); + mutex_destroy(&sensor->ksensor_mutex); + kmem_free(sensor, sizeof (ksensor_t)); +} + +static void +ksensor_free_dip(ksensor_dip_t *ksdip) +{ + list_destroy(&ksdip->ksdip_sensors); + kmem_free(ksdip, sizeof (ksensor_dip_t)); +} + +static void +ksensor_dip_unbind_taskq(void *arg) +{ + ksensor_dip_t *k = arg; + ksensor_t *sensor; + + /* + * First notify an attached driver that the nodes are going away + * before we block and wait on them. + */ + mutex_enter(&ksensor_g_mutex); + for (sensor = list_head(&k->ksdip_sensors); sensor != NULL; + sensor = list_next(&k->ksdip_sensors, sensor)) { + mutex_enter(&sensor->ksensor_mutex); + if (sensor->ksensor_flags & KSENSOR_F_NOTIFIED) { + ksensor_cb_remove(sensor->ksensor_id, + sensor->ksensor_name); + sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED; + } + mutex_exit(&sensor->ksensor_mutex); + } + mutex_exit(&ksensor_g_mutex); + + /* + * Now that the driver has destroyed its minor, wait for anything that's + * still there. + */ + while ((sensor = list_remove_head(&k->ksdip_sensors)) != NULL) { + mutex_enter(&sensor->ksensor_mutex); + while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0 || + sensor->ksensor_nwaiters > 0) { + cv_wait(&sensor->ksensor_cv, &sensor->ksensor_mutex); + } + mutex_exit(&sensor->ksensor_mutex); + ksensor_free_sensor(sensor); + } + ksensor_free_dip(k); +} + +static void +ksensor_dip_unbind_cb(void *arg, dev_info_t *dip) +{ + ksensor_dip_t *k = arg; + ksensor_t *sensor; + + /* + * Remove the dip and the associated sensors from global visibility. + * This will ensure that no new clients can find this; however, others + * may have extent attempts to grab it (but lost the race in an NDI + * hold). + */ + mutex_enter(&ksensor_g_mutex); + list_remove(&ksensor_dips, k); + k->ksdip_flags |= KSENSOR_DIP_F_REMOVED; + for (sensor = list_head(&k->ksdip_sensors); sensor != NULL; + sensor = list_next(&k->ksdip_sensors, sensor)) { + avl_remove(&ksensor_avl, sensor); + } + mutex_exit(&ksensor_g_mutex); + + (void) taskq_dispatch(system_taskq, ksensor_dip_unbind_taskq, k, + TQ_SLEEP); +} + +static ksensor_dip_t * +ksensor_dip_create(dev_info_t *dip) +{ + ksensor_dip_t *k; + + k = kmem_zalloc(sizeof (ksensor_dip_t), KM_SLEEP); + k->ksdip_dip = dip; + k->ksdip_cb.ddiub_cb = ksensor_dip_unbind_cb; + k->ksdip_cb.ddiub_arg = k; + list_create(&k->ksdip_sensors, sizeof (ksensor_t), + offsetof(ksensor_t, ksensor_dip_list)); + e_ddi_register_unbind_callback(dip, &k->ksdip_cb); + + return (k); +} + +static ksensor_dip_t * +ksensor_dip_find(dev_info_t *dip) +{ + ksensor_dip_t *k; + + ASSERT(MUTEX_HELD(&ksensor_g_mutex)); + for (k = list_head(&ksensor_dips); k != NULL; + k = list_next(&ksensor_dips, k)) { + if (dip == k->ksdip_dip) { + return (k); + } + } + + return (NULL); +} + +int +ksensor_create(dev_info_t *dip, const ksensor_ops_t *ops, void *arg, + const char *name, const char *class, id_t *idp) +{ + ksensor_dip_t *ksdip; + ksensor_t *sensor; + + if (dip == NULL || ops == NULL || name == NULL || class == NULL || + idp == NULL) { + return (EINVAL); + } + + if (!DEVI_IS_ATTACHING(dip)) { + return (EAGAIN); + } + + mutex_enter(&ksensor_g_mutex); + ksdip = ksensor_dip_find(dip); + if (ksdip == NULL) { + ksdip = ksensor_dip_create(dip); + list_insert_tail(&ksensor_dips, ksdip); + } + + sensor = ksensor_search_ksdip(ksdip, name, class); + if (sensor != NULL) { + ASSERT3P(sensor->ksensor_ksdip, ==, ksdip); + if ((sensor->ksensor_flags & KSENSOR_F_VALID) != 0) { + mutex_exit(&ksensor_g_mutex); + dev_err(dip, CE_WARN, "tried to create sensor %s:%s " + "which is currently active", class, name); + return (EEXIST); + } + + sensor->ksensor_ops = ops; + sensor->ksensor_arg = arg; + } else { + sensor = kmem_zalloc(sizeof (ksensor_t), KM_SLEEP); + sensor->ksensor_ksdip = ksdip; + sensor->ksensor_name = ddi_strdup(name, KM_SLEEP); + sensor->ksensor_class = ddi_strdup(class, KM_SLEEP); + sensor->ksensor_id = id_alloc(ksensor_ids); + sensor->ksensor_ops = ops; + sensor->ksensor_arg = arg; + list_insert_tail(&ksdip->ksdip_sensors, sensor); + avl_add(&ksensor_avl, sensor); + } + + sensor->ksensor_flags |= KSENSOR_F_VALID; + + if (ksensor_cb_create != NULL) { + + if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class, + sensor->ksensor_name) == 0) { + sensor->ksensor_flags |= KSENSOR_F_NOTIFIED; + } + } + + *idp = sensor->ksensor_id; + mutex_exit(&ksensor_g_mutex); + + return (0); +} + +int +ksensor_create_temp_pcidev(dev_info_t *dip, const ksensor_ops_t *ops, + void *arg, const char *name, id_t *idp) +{ + char *pci_name, *type; + int *regs, ret; + uint_t nregs; + uint16_t bus, dev; + + if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "device_type", + &type) != DDI_PROP_SUCCESS) { + return (EINVAL); + } + + if (strcmp(type, "pciex") != 0 && strcmp(type, "pci") != 0) { + ddi_prop_free(type); + return (EINVAL); + } + ddi_prop_free(type); + + if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, "reg", + ®s, &nregs) != DDI_PROP_SUCCESS) { + return (EINVAL); + } + + if (nregs < 1) { + ddi_prop_free(regs); + return (EIO); + } + + bus = PCI_REG_BUS_G(regs[0]); + dev = PCI_REG_DEV_G(regs[0]); + ddi_prop_free(regs); + + pci_name = kmem_asprintf("%x.%x:%s", bus, dev, name); + + ret = ksensor_create(dip, ops, arg, pci_name, + "ddi_sensor:temperature:pci", idp); + strfree(pci_name); + return (ret); +} + +/* + * When a driver removes a sensor, we basically mark it as invalid. This happens + * because drivers can detach and we will need to reattach them when the sensor + * is used again. + */ +int +ksensor_remove(dev_info_t *dip, id_t id) +{ + ksensor_dip_t *kdip; + ksensor_t *sensor; + + if (!DEVI_IS_ATTACHING(dip) && !DEVI_IS_DETACHING(dip)) { + return (EAGAIN); + } + + mutex_enter(&ksensor_g_mutex); + kdip = ksensor_dip_find(dip); + if (kdip == NULL) { + mutex_exit(&ksensor_g_mutex); + return (ENOENT); + } + + for (sensor = list_head(&kdip->ksdip_sensors); sensor != NULL; + sensor = list_next(&kdip->ksdip_sensors, sensor)) { + if (sensor->ksensor_id == id || id == KSENSOR_ALL_IDS) { + mutex_enter(&sensor->ksensor_mutex); + sensor->ksensor_flags &= ~KSENSOR_F_VALID; + sensor->ksensor_ops = NULL; + sensor->ksensor_arg = NULL; + mutex_exit(&sensor->ksensor_mutex); + } + } + mutex_exit(&ksensor_g_mutex); + return (0); +} + +static void +ksensor_release(ksensor_t *sensor) +{ + int circ; + dev_info_t *pdip; + + ddi_release_devi(sensor->ksensor_ksdip->ksdip_dip); + + mutex_enter(&sensor->ksensor_mutex); + sensor->ksensor_flags &= ~KSENSOR_F_BUSY; + cv_broadcast(&sensor->ksensor_cv); + mutex_exit(&sensor->ksensor_mutex); +} + +static int +ksensor_hold_by_id(id_t id, ksensor_t **outp) +{ + int circ; + ksensor_t *sensor; + dev_info_t *pdip; + +restart: + mutex_enter(&ksensor_g_mutex); + sensor = ksensor_find_by_id(id); + if (sensor == NULL) { + mutex_exit(&ksensor_g_mutex); + *outp = NULL; + return (ESTALE); + } + + if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) { + mutex_exit(&ksensor_g_mutex); + *outp = NULL; + return (ESTALE); + } + + mutex_enter(&sensor->ksensor_mutex); + if ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) { + mutex_exit(&ksensor_g_mutex); + sensor->ksensor_nwaiters++; + while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) { + int cv = cv_wait_sig(&sensor->ksensor_cv, + &sensor->ksensor_mutex); + if (cv == 0) { + sensor->ksensor_nwaiters--; + cv_broadcast(&sensor->ksensor_cv); + mutex_exit(&sensor->ksensor_mutex); + *outp = NULL; + return (EINTR); + } + } + sensor->ksensor_nwaiters--; + cv_broadcast(&sensor->ksensor_cv); + mutex_exit(&sensor->ksensor_mutex); + goto restart; + } + + /* + * We have obtained ownership of the sensor. At this point, we should + * check to see if it's valid or not. + */ + sensor->ksensor_flags |= KSENSOR_F_BUSY; + pdip = ddi_get_parent(sensor->ksensor_ksdip->ksdip_dip); + mutex_exit(&sensor->ksensor_mutex); + mutex_exit(&ksensor_g_mutex); + + /* + * Grab a reference on the device node to ensure that it won't go away. + */ + ndi_devi_enter(pdip, &circ); + e_ddi_hold_devi(sensor->ksensor_ksdip->ksdip_dip); + ndi_devi_exit(pdip, circ); + + /* + * Now that we have an NDI hold, check if it's valid or not. It may have + * become invalid while we were waiting due to a race. + */ + mutex_enter(&ksensor_g_mutex); + if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) { + mutex_exit(&ksensor_g_mutex); + ksensor_release(sensor); + return (ESTALE); + } + + mutex_enter(&sensor->ksensor_mutex); + if ((sensor->ksensor_flags & KSENSOR_F_VALID) == 0) { + mutex_exit(&sensor->ksensor_mutex); + mutex_exit(&ksensor_g_mutex); + (void) ndi_devi_config(pdip, NDI_NO_EVENT); + mutex_enter(&ksensor_g_mutex); + mutex_enter(&sensor->ksensor_mutex); + + /* + * If we attempted to reattach it and it isn't now valid, fail + * this request. + */ + if ((sensor->ksensor_ksdip->ksdip_flags & + KSENSOR_DIP_F_REMOVED) != 0 || + (sensor->ksensor_flags & KSENSOR_F_VALID) == 0) { + mutex_exit(&sensor->ksensor_mutex); + mutex_exit(&ksensor_g_mutex); + ksensor_release(sensor); + return (ESTALE); + } + } + mutex_exit(&sensor->ksensor_mutex); + mutex_exit(&ksensor_g_mutex); + *outp = sensor; + + return (0); +} + +int +ksensor_op_kind(id_t id, sensor_ioctl_kind_t *kind) +{ + int ret; + ksensor_t *sensor; + + if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) { + return (ret); + } + + ret = sensor->ksensor_ops->kso_kind(sensor->ksensor_arg, kind); + ksensor_release(sensor); + + return (ret); +} + +int +ksensor_op_temperature(id_t id, sensor_ioctl_temperature_t *temp) +{ + int ret; + ksensor_t *sensor; + + if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) { + return (ret); + } + + ret = sensor->ksensor_ops->kso_temp(sensor->ksensor_arg, temp); + ksensor_release(sensor); + + return (ret); +} + +void +ksensor_unregister(dev_info_t *reg_dip) +{ + ksensor_t *sensor; + + mutex_enter(&ksensor_g_mutex); + if (ksensor_cb_dip != reg_dip) { + dev_err(reg_dip, CE_PANIC, "asked to unregister illegal dip"); + } + + for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor = + AVL_NEXT(&ksensor_avl, sensor)) { + mutex_enter(&sensor->ksensor_mutex); + sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED; + mutex_exit(&sensor->ksensor_mutex); + } + + ksensor_cb_dip = NULL; + ksensor_cb_create = NULL; + ksensor_cb_remove = NULL; + mutex_exit(&ksensor_g_mutex); +} + +int +ksensor_register(dev_info_t *reg_dip, ksensor_create_f create, + ksensor_remove_f remove) +{ + ksensor_t *sensor; + + mutex_enter(&ksensor_g_mutex); + if (ksensor_cb_dip != NULL) { + dev_err(reg_dip, CE_WARN, "kernel sensors are already " + "registered"); + mutex_exit(&ksensor_g_mutex); + return (EEXIST); + } + + ksensor_cb_dip = reg_dip; + ksensor_cb_create = create; + ksensor_cb_remove = remove; + + for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor = + AVL_NEXT(&ksensor_avl, sensor)) { + mutex_enter(&sensor->ksensor_mutex); + ASSERT0(sensor->ksensor_flags & KSENSOR_F_NOTIFIED); + + if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class, + sensor->ksensor_name) == 0) { + sensor->ksensor_flags |= KSENSOR_F_NOTIFIED; + } + + mutex_exit(&sensor->ksensor_mutex); + } + + mutex_exit(&ksensor_g_mutex); + + return (0); +} + +int +ksensor_kind_temperature(void *unused, sensor_ioctl_kind_t *k) +{ + k->sik_kind = SENSOR_KIND_TEMPERATURE; + return (0); +} + +void +ksensor_init(void) +{ + mutex_init(&ksensor_g_mutex, NULL, MUTEX_DRIVER, NULL); + list_create(&ksensor_dips, sizeof (ksensor_dip_t), + offsetof(ksensor_dip_t, ksdip_link)); + ksensor_ids = id_space_create("ksensor", 1, L_MAXMIN32); + avl_create(&ksensor_avl, ksensor_avl_compare, sizeof (ksensor_t), + offsetof(ksensor_t, ksensor_id_avl)); +}
--- a/usr/src/uts/common/sys/ddi_impldefs.h Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/sys/ddi_impldefs.h Sat Apr 04 21:20:18 2020 -0700 @@ -289,6 +289,12 @@ /* detach event data */ char *devi_ev_path; int devi_ev_instance; + + /* + * Unbind callback data. + */ + kmutex_t devi_unbind_lock; + list_t devi_unbind_cbs; }; #define DEVI(dev_info_type) ((struct dev_info *)(dev_info_type))
--- a/usr/src/uts/common/sys/esunddi.h Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/sys/esunddi.h Sat Apr 04 21:20:18 2020 -0700 @@ -22,6 +22,7 @@ * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright 2020 Oxide Computer Company */ #ifndef _SYS_ESUNDDI_H @@ -46,15 +47,15 @@ int e_ddi_prop_create(dev_t dev, dev_info_t *dip, int flag, - char *name, caddr_t value, int length); + char *name, caddr_t value, int length); int e_ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag, - char *name, caddr_t value, int length); + char *name, caddr_t value, int length); int e_ddi_prop_update_int(dev_t match_dev, dev_info_t *dip, - char *name, int data); + char *name, int data); int e_ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip, @@ -70,7 +71,7 @@ int e_ddi_prop_update_string(dev_t match_dev, dev_info_t *dip, - char *name, char *data); + char *name, char *data); int e_ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip, @@ -94,18 +95,18 @@ int64_t e_ddi_getprop_int64(dev_t dev, vtype_t type, char *name, - int flags, int64_t defvalue); + int flags, int64_t defvalue); int e_ddi_getproplen(dev_t dev, vtype_t type, char *name, int flags, int *lengthp); int e_ddi_getlongprop(dev_t dev, vtype_t type, char *name, int flags, - caddr_t valuep, int *lengthp); + caddr_t valuep, int *lengthp); int e_ddi_getlongprop_buf(dev_t dev, vtype_t type, char *name, int flags, - caddr_t valuep, int *lengthp); + caddr_t valuep, int *lengthp); int e_ddi_parental_suspend_resume(dev_info_t *dip); @@ -159,9 +160,8 @@ */ int umem_lockmemory(caddr_t addr, size_t size, int flags, - ddi_umem_cookie_t *cookie, - struct umem_callback_ops *ops_vector, - proc_t *procp); + ddi_umem_cookie_t *cookie, struct umem_callback_ops *ops_vector, + proc_t *procp); #define DDI_UMEMLOCK_LONGTERM 0x04 @@ -249,15 +249,20 @@ * Obsolete interfaces, no longer used, to be removed. * Retained only for driver compatibility. */ -void -e_ddi_enter_driver_list(struct devnames *, int *); /* obsolete */ +void e_ddi_enter_driver_list(struct devnames *, int *); /* obsolete */ + +int e_ddi_tryenter_driver_list(struct devnames *, int *); /* obsolete */ + +void e_ddi_exit_driver_list(struct devnames *, int); /* obsolete */ -int -e_ddi_tryenter_driver_list(struct devnames *, int *); /* obsolete */ +typedef struct ddi_unbind_callback { + list_node_t ddiub_next; + void (*ddiub_cb)(void *, dev_info_t *); + void *ddiub_arg; +} ddi_unbind_callback_t; -void -e_ddi_exit_driver_list(struct devnames *, int); /* obsolete */ - +extern void e_ddi_register_unbind_callback(dev_info_t *, + ddi_unbind_callback_t *); #endif /* _KERNEL */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/sys/ksensor_impl.h Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,52 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2020 Oxide Computer Company + */ + +#ifndef _SYS_KSENSOR_IMPL_H +#define _SYS_KSENSOR_IMPL_H + +/* + * ksensor implementation glue. + */ + +#include <sys/sensors.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Routine for the kernel to initalize the subsystem. + */ +extern void ksensor_init(void); + +/* + * Operations vectors. + */ +extern int ksensor_op_kind(id_t, sensor_ioctl_kind_t *); +extern int ksensor_op_temperature(id_t, sensor_ioctl_temperature_t *); + +/* + * Registration callbacks. + */ +typedef int (*ksensor_create_f)(id_t, const char *, const char *); +typedef void (*ksensor_remove_f)(id_t, const char *); +extern int ksensor_register(dev_info_t *, ksensor_create_f, ksensor_remove_f); +extern void ksensor_unregister(dev_info_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_KSENSOR_IMPL_H */
--- a/usr/src/uts/common/sys/sensors.h Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/common/sys/sensors.h Sat Apr 04 21:20:18 2020 -0700 @@ -11,6 +11,7 @@ /* * Copyright 2019, Joyent, Inc. + * Copyright 2020 Oxide Computer Company */ #ifndef _SYS_SENSORS_H @@ -71,9 +72,43 @@ typedef struct sensor_ioctl_temperature { uint32_t sit_unit; int32_t sit_gran; + uint32_t sit_prec; + uint32_t sit_pad; int64_t sit_temp; } sensor_ioctl_temperature_t; +#ifdef _KERNEL +typedef int (*ksensor_kind_f)(void *, sensor_ioctl_kind_t *); +typedef int (*ksensor_temp_f)(void *, sensor_ioctl_temperature_t *); + +typedef struct { + ksensor_kind_f kso_kind; + ksensor_temp_f kso_temp; +} ksensor_ops_t; + +extern int ksensor_kind_temperature(void *, sensor_ioctl_kind_t *); + +/* + * Create a sensor where the class and name is supplied. + */ +extern int ksensor_create(dev_info_t *, const ksensor_ops_t *, void *, + const char *, const char *, id_t *); + +/* + * Create a temperature sensor for a PCI device. If this is not a device-wide + * (e.g. per-function) sensor, this should not be used. + */ +extern int ksensor_create_temp_pcidev(dev_info_t *, const ksensor_ops_t *, + void *, const char *, id_t *); + +/* + * Remove a named or all sensors from this driver. + */ +#define KSENSOR_ALL_IDS INT_MIN +extern int ksensor_remove(dev_info_t *, id_t); + +#endif + #ifdef __cplusplus } #endif
--- a/usr/src/uts/intel/Makefile.intel Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/intel/Makefile.intel Sat Apr 04 21:20:18 2020 -0700 @@ -765,6 +765,7 @@ # # Sensor related drivers # +DRV_KMODS += ksensor ksensor_test DRV_KMODS += amdf17nbdf DRV_KMODS += coretemp DRV_KMODS += pchtemp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/ksensor/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,40 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +UTSBASE = ../.. + +MODULE = ksensor +OBJECTS = $(KSENSOR_OBJS:%=$(OBJS_DIR)/%) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/ksensor + +include $(UTSBASE)/intel/Makefile.intel + +ALL_TARGET = $(BINARY) $(CONFMOD) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +install: $(INSTALL_DEPS) + +include $(UTSBASE)/intel/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/intel/ksensor_test/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,40 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +UTSBASE = ../.. + +MODULE = ksensor_test +OBJECTS = $(KSENSOR_TEST_OBJS:%=$(OBJS_DIR)/%) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/ksensor + +include $(UTSBASE)/intel/Makefile.intel + +ALL_TARGET = $(BINARY) $(CONFMOD) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +install: $(INSTALL_DEPS) + +include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/sparc/Makefile.sparc Thu Jun 25 01:45:50 2020 +0000 +++ b/usr/src/uts/sparc/Makefile.sparc Sat Apr 04 21:20:18 2020 -0700 @@ -531,3 +531,8 @@ # $(LINTFLAGSUPPRESS)LINTFLAGS += -D_MACHDEP -I$(UTSBASE)/sun4 \ -I$(UTSBASE)/sun4u -I$(UTSBASE)/sfmmu + +# +# Sensor related drivers +# +DRV_KMODS += ksensor ksensor_test
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/ksensor/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,40 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +UTSBASE = ../.. + +MODULE = ksensor +OBJECTS = $(KSENSOR_OBJS:%=$(OBJS_DIR)/%) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/ksensor + +include $(UTSBASE)/sparc/Makefile.sparc + +ALL_TARGET = $(BINARY) $(CONFMOD) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +install: $(INSTALL_DEPS) + +include $(UTSBASE)/sparc/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/sparc/ksensor_test/Makefile Sat Apr 04 21:20:18 2020 -0700 @@ -0,0 +1,40 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# + +UTSBASE = ../.. + +MODULE = ksensor_test +OBJECTS = $(KSENSOR_TEST_OBJS:%=$(OBJS_DIR)/%) +ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) +CONF_SRCDIR = $(UTSBASE)/common/io/ksensor + +include $(UTSBASE)/sparc/Makefile.sparc + +ALL_TARGET = $(BINARY) $(CONFMOD) +INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE) + +.KEEP_STATE: + +def: $(DEF_DEPS) + +all: $(ALL_DEPS) + +clean: $(CLEAN_DEPS) + +clobber: $(CLOBBER_DEPS) + +install: $(INSTALL_DEPS) + +include $(UTSBASE)/sparc/Makefile.targ