summaryrefslogtreecommitdiff
path: root/sys/dev/pv
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2017-01-21 11:23:15 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2017-01-21 11:23:15 +0000
commit8ff75b4936e9c8d996abea80cd133d1d75dd4446 (patch)
tree5fe616eb69393902e7bac7f67f71b4f3a31b55d1 /sys/dev/pv
parenta5fb8bb27e1d4907bef569ffe7db669716d9c63a (diff)
Move vmmci.c to sys/dev/pv/vmmci.c
virtio itself is not PCI, it is a paravirtual bus on top of either PCI or MMIO (arm). This is the second step of moving the virtio files to dev/pv. No functional change. Moving the file is done by removing and adding it again - the old history can be found in the Attic of sys/dev/pci/vmmci.c. no objections from sf@ mlarkin@
Diffstat (limited to 'sys/dev/pv')
-rw-r--r--sys/dev/pv/vmmci.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/sys/dev/pv/vmmci.c b/sys/dev/pv/vmmci.c
new file mode 100644
index 00000000000..1dfd5e7eaf2
--- /dev/null
+++ b/sys/dev/pv/vmmci.c
@@ -0,0 +1,183 @@
+/* $OpenBSD: vmmci.c,v 1.1 2017/01/21 11:23:14 reyk Exp $ */
+
+/*
+ * Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/timeout.h>
+#include <sys/signalvar.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/pool.h>
+#include <sys/proc.h>
+
+#include <machine/bus.h>
+
+#include <dev/pv/virtioreg.h>
+#include <dev/pv/virtiovar.h>
+#include <dev/pv/pvvar.h>
+#include <dev/rndvar.h>
+
+enum vmmci_cmd {
+ VMMCI_NONE = 0,
+ VMMCI_SHUTDOWN,
+ VMMCI_REBOOT,
+};
+
+struct vmmci_softc {
+ struct device sc_dev;
+ struct virtio_softc *sc_virtio;
+ enum vmmci_cmd sc_cmd;
+ unsigned int sc_interval;
+ struct ksensordev sc_sensordev;
+ struct ksensor sc_sensor;
+ struct timeout sc_tick;
+};
+
+int vmmci_match(struct device *, void *, void *);
+void vmmci_attach(struct device *, struct device *, void *);
+
+int vmmci_config_change(struct virtio_softc *);
+void vmmci_tick(void *);
+void vmmci_tick_hook(struct device *);
+
+struct cfattach vmmci_ca = {
+ sizeof(struct vmmci_softc),
+ vmmci_match,
+ vmmci_attach,
+ NULL
+};
+
+/* Configuration registers */
+#define VMMCI_CONFIG_COMMAND 0
+#define VMMCI_CONFIG_TIME_SEC 4
+#define VMMCI_CONFIG_TIME_USEC 12
+
+/* Feature bits */
+#define VMMCI_F_TIMESYNC (1<<0)
+
+struct cfdriver vmmci_cd = {
+ NULL, "vmmci", DV_DULL
+};
+
+int
+vmmci_match(struct device *parent, void *match, void *aux)
+{
+ struct virtio_softc *va = aux;
+ if (va->sc_childdevid == PCI_PRODUCT_VIRTIO_VMMCI)
+ return (1);
+ return (0);
+}
+
+void
+vmmci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct vmmci_softc *sc = (struct vmmci_softc *)self;
+ struct virtio_softc *vsc = (struct virtio_softc *)parent;
+ uint32_t features;
+
+ if (vsc->sc_child != NULL)
+ panic("already attached to something else");
+
+ vsc->sc_child = self;
+ vsc->sc_nvqs = 0;
+ vsc->sc_config_change = vmmci_config_change;
+ vsc->sc_ipl = IPL_NET;
+ sc->sc_virtio = vsc;
+
+ features = VMMCI_F_TIMESYNC;
+ features = virtio_negotiate_features(vsc, features, NULL);
+
+ if (features & VMMCI_F_TIMESYNC) {
+ strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
+ sizeof(sc->sc_sensordev.xname));
+ sc->sc_sensor.type = SENSOR_TIMEDELTA;
+ sc->sc_sensor.status = SENSOR_S_UNKNOWN;
+ sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
+ sensordev_install(&sc->sc_sensordev);
+
+ config_mountroot(self, vmmci_tick_hook);
+ }
+
+ printf("\n");
+}
+
+int
+vmmci_config_change(struct virtio_softc *vsc)
+{
+ struct vmmci_softc *sc = (struct vmmci_softc *)vsc->sc_child;
+ int cmd;
+
+ /* Check for command */
+ cmd = virtio_read_device_config_1(vsc, VMMCI_CONFIG_COMMAND);
+ if (cmd == sc->sc_cmd)
+ return (0);
+ sc->sc_cmd = cmd;
+
+ switch (cmd) {
+ case VMMCI_NONE:
+ /* no action */
+ break;
+ case VMMCI_SHUTDOWN:
+ pvbus_shutdown(&sc->sc_dev);
+ break;
+ case VMMCI_REBOOT:
+ pvbus_reboot(&sc->sc_dev);
+ break;
+ default:
+ printf("%s: invalid command %d\n", sc->sc_dev.dv_xname, cmd);
+ break;
+ }
+
+ return (1);
+}
+
+void
+vmmci_tick(void *arg)
+{
+ struct vmmci_softc *sc = arg;
+ struct virtio_softc *vsc = sc->sc_virtio;
+ struct timeval *guest = &sc->sc_sensor.tv;
+ struct timeval host, diff;
+
+ microtime(guest);
+
+ /* Update time delta sensor */
+ host.tv_sec = virtio_read_device_config_8(vsc, VMMCI_CONFIG_TIME_SEC);
+ host.tv_usec = virtio_read_device_config_8(vsc, VMMCI_CONFIG_TIME_USEC);
+
+ if (host.tv_usec > 0) {
+ timersub(guest, &host, &diff);
+
+ sc->sc_sensor.value = (uint64_t)diff.tv_sec * 1000000000LL +
+ (uint64_t)diff.tv_usec * 1000LL;
+ sc->sc_sensor.status = SENSOR_S_OK;
+ } else
+ sc->sc_sensor.status = SENSOR_S_UNKNOWN;
+
+ timeout_add_sec(&sc->sc_tick, 15);
+}
+
+void
+vmmci_tick_hook(struct device *self)
+{
+ struct vmmci_softc *sc = (struct vmmci_softc *)self;
+
+ timeout_set(&sc->sc_tick, vmmci_tick, sc);
+ vmmci_tick(sc);
+}