]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hyperv/vmbus/hv_et.c
hyperv: Set vm_guest to VM_GUEST_VM, if hypervisor is not Hyper-V
[FreeBSD/FreeBSD.git] / sys / dev / hyperv / vmbus / hv_et.c
1 /*-
2  * Copyright (c) 2015,2016 Microsoft Corp.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *      notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *      notice, this list of conditions and the following disclaimer in the
12  *      documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/proc.h>
35 #include <sys/systm.h>
36 #include <sys/smp.h>
37 #include <sys/time.h>
38 #include <sys/timeet.h>
39
40 #include "hv_vmbus_priv.h"
41
42 #define HV_TIMER_FREQUENCY              (10 * 1000 * 1000LL) /* 100ns period */
43 #define HV_MAX_DELTA_TICKS              0xffffffffLL
44 #define HV_MIN_DELTA_TICKS              1LL
45
46 static struct eventtimer *et;
47
48 static inline uint64_t
49 sbintime2tick(sbintime_t time)
50 {
51         struct timespec val;
52
53         val = sbttots(time);
54         return val.tv_sec * HV_TIMER_FREQUENCY + val.tv_nsec / 100;
55 }
56
57 static int
58 hv_et_start(struct eventtimer *et, sbintime_t firsttime, sbintime_t periodtime)
59 {
60         union hv_timer_config timer_cfg;
61         uint64_t current;
62
63         timer_cfg.as_uint64 = 0;
64         timer_cfg.auto_enable = 1;
65         timer_cfg.sintx = HV_VMBUS_TIMER_SINT;
66
67         current = rdmsr(HV_X64_MSR_TIME_REF_COUNT);
68         current += sbintime2tick(firsttime);
69
70         wrmsr(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
71         wrmsr(HV_X64_MSR_STIMER0_COUNT, current);
72
73         return (0);
74 }
75
76 static int
77 hv_et_stop(struct eventtimer *et)
78 {
79         wrmsr(HV_X64_MSR_STIMER0_CONFIG, 0);
80         wrmsr(HV_X64_MSR_STIMER0_COUNT, 0);
81
82         return (0);
83 }
84
85 void
86 hv_et_intr(struct trapframe *frame)
87 {
88         struct trapframe *oldframe;
89         struct thread *td;
90
91         if (et->et_active) {
92                 td = curthread;
93                 td->td_intr_nesting_level++;
94                 oldframe = td->td_intr_frame;
95                 td->td_intr_frame = frame;
96                 et->et_event_cb(et, et->et_arg);
97                 td->td_intr_frame = oldframe;
98                 td->td_intr_nesting_level--;
99         }
100 }
101
102 static void
103 hv_et_identify(driver_t *driver, device_t parent)
104 {
105         if (device_find_child(parent, "hv_et", -1) != NULL)
106                 return;
107
108         device_add_child(parent, "hv_et", -1);
109 }
110
111 static int
112 hv_et_probe(device_t dev)
113 {
114         device_set_desc(dev, "Hyper-V event timer");
115
116         return (BUS_PROBE_NOWILDCARD);
117 }
118
119 static int
120 hv_et_attach(device_t dev)
121 {
122         /* XXX: need allocate SINT and remove global et */
123         et = device_get_softc(dev);
124
125         et->et_name = "Hyper-V";
126         et->et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
127         et->et_quality = 1000;
128         et->et_frequency = HV_TIMER_FREQUENCY;
129         et->et_min_period = HV_MIN_DELTA_TICKS * ((1LL << 32) / HV_TIMER_FREQUENCY);
130         et->et_max_period = HV_MAX_DELTA_TICKS * ((1LL << 32) / HV_TIMER_FREQUENCY);
131         et->et_start = hv_et_start;
132         et->et_stop = hv_et_stop;
133         et->et_priv = dev;
134
135         return (et_register(et));
136 }
137
138 static int
139 hv_et_detach(device_t dev)
140 {
141         return (et_deregister(et));
142 }
143
144 static device_method_t hv_et_methods[] = {
145         DEVMETHOD(device_identify,      hv_et_identify),
146         DEVMETHOD(device_probe,         hv_et_probe),
147         DEVMETHOD(device_attach,        hv_et_attach),
148         DEVMETHOD(device_detach,        hv_et_detach),
149
150         DEVMETHOD_END
151 };
152
153 static driver_t hv_et_driver = {
154         "hv_et",
155         hv_et_methods,
156         sizeof(struct eventtimer)
157 };
158
159 static devclass_t hv_et_devclass;
160 DRIVER_MODULE(hv_et, vmbus, hv_et_driver, hv_et_devclass, NULL, 0);
161 MODULE_VERSION(hv_et, 1);