~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/staging/hv/hv_utils.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2010, Microsoft Corporation.
3
 
 *
4
 
 * This program is free software; you can redistribute it and/or modify it
5
 
 * under the terms and conditions of the GNU General Public License,
6
 
 * version 2, as published by the Free Software Foundation.
7
 
 *
8
 
 * This program is distributed in the hope it will be useful, but WITHOUT
9
 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11
 
 * more details.
12
 
 *
13
 
 * You should have received a copy of the GNU General Public License along with
14
 
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
 
 * Place - Suite 330, Boston, MA 02111-1307 USA.
16
 
 *
17
 
 * Authors:
18
 
 *   Haiyang Zhang <haiyangz@microsoft.com>
19
 
 *   Hank Janssen  <hjanssen@microsoft.com>
20
 
 */
21
 
#include <linux/kernel.h>
22
 
#include <linux/init.h>
23
 
#include <linux/module.h>
24
 
#include <linux/slab.h>
25
 
#include <linux/sysctl.h>
26
 
#include <linux/reboot.h>
27
 
#include <linux/dmi.h>
28
 
#include <linux/pci.h>
29
 
 
30
 
#include "logging.h"
31
 
#include "osd.h"
32
 
#include "vmbus.h"
33
 
#include "vmbus_packet_format.h"
34
 
#include "vmbus_channel_interface.h"
35
 
#include "version_info.h"
36
 
#include "channel.h"
37
 
#include "vmbus_private.h"
38
 
#include "vmbus_api.h"
39
 
#include "utils.h"
40
 
 
41
 
static u8 *shut_txf_buf;
42
 
static u8 *time_txf_buf;
43
 
static u8 *hbeat_txf_buf;
44
 
 
45
 
static void shutdown_onchannelcallback(void *context)
46
 
{
47
 
        struct vmbus_channel *channel = context;
48
 
        u32 recvlen;
49
 
        u64 requestid;
50
 
        u8  execute_shutdown = false;
51
 
 
52
 
        struct shutdown_msg_data *shutdown_msg;
53
 
 
54
 
        struct icmsg_hdr *icmsghdrp;
55
 
        struct icmsg_negotiate *negop = NULL;
56
 
 
57
 
        vmbus_recvpacket(channel, shut_txf_buf,
58
 
                         PAGE_SIZE, &recvlen, &requestid);
59
 
 
60
 
        if (recvlen > 0) {
61
 
                DPRINT_DBG(VMBUS, "shutdown packet: len=%d, requestid=%lld",
62
 
                           recvlen, requestid);
63
 
 
64
 
                icmsghdrp = (struct icmsg_hdr *)&shut_txf_buf[
65
 
                        sizeof(struct vmbuspipe_hdr)];
66
 
 
67
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
68
 
                        prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
69
 
                } else {
70
 
                        shutdown_msg =
71
 
                                (struct shutdown_msg_data *)&shut_txf_buf[
72
 
                                        sizeof(struct vmbuspipe_hdr) +
73
 
                                        sizeof(struct icmsg_hdr)];
74
 
 
75
 
                        switch (shutdown_msg->flags) {
76
 
                        case 0:
77
 
                        case 1:
78
 
                                icmsghdrp->status = HV_S_OK;
79
 
                                execute_shutdown = true;
80
 
 
81
 
                                DPRINT_INFO(VMBUS, "Shutdown request received -"
82
 
                                            " gracefull shutdown initiated");
83
 
                                break;
84
 
                        default:
85
 
                                icmsghdrp->status = HV_E_FAIL;
86
 
                                execute_shutdown = false;
87
 
 
88
 
                                DPRINT_INFO(VMBUS, "Shutdown request received -"
89
 
                                            " Invalid request");
90
 
                                break;
91
 
                        };
92
 
                }
93
 
 
94
 
                icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
95
 
                        | ICMSGHDRFLAG_RESPONSE;
96
 
 
97
 
                vmbus_sendpacket(channel, shut_txf_buf,
98
 
                                       recvlen, requestid,
99
 
                                       VmbusPacketTypeDataInBand, 0);
100
 
        }
101
 
 
102
 
        if (execute_shutdown == true)
103
 
                orderly_poweroff(false);
104
 
}
105
 
 
106
 
/*
107
 
 * Set guest time to host UTC time.
108
 
 */
109
 
static inline void do_adj_guesttime(u64 hosttime)
110
 
{
111
 
        s64 host_tns;
112
 
        struct timespec host_ts;
113
 
 
114
 
        host_tns = (hosttime - WLTIMEDELTA) * 100;
115
 
        host_ts = ns_to_timespec(host_tns);
116
 
 
117
 
        do_settimeofday(&host_ts);
118
 
}
119
 
 
120
 
/*
121
 
 * Synchronize time with host after reboot, restore, etc.
122
 
 *
123
 
 * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
124
 
 * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
125
 
 * message after the timesync channel is opened. Since the hv_utils module is
126
 
 * loaded after hv_vmbus, the first message is usually missed. The other
127
 
 * thing is, systime is automatically set to emulated hardware clock which may
128
 
 * not be UTC time or in the same time zone. So, to override these effects, we
129
 
 * use the first 50 time samples for initial system time setting.
130
 
 */
131
 
static inline void adj_guesttime(u64 hosttime, u8 flags)
132
 
{
133
 
        static s32 scnt = 50;
134
 
 
135
 
        if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
136
 
                do_adj_guesttime(hosttime);
137
 
                return;
138
 
        }
139
 
 
140
 
        if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
141
 
                scnt--;
142
 
                do_adj_guesttime(hosttime);
143
 
        }
144
 
}
145
 
 
146
 
/*
147
 
 * Time Sync Channel message handler.
148
 
 */
149
 
static void timesync_onchannelcallback(void *context)
150
 
{
151
 
        struct vmbus_channel *channel = context;
152
 
        u32 recvlen;
153
 
        u64 requestid;
154
 
        struct icmsg_hdr *icmsghdrp;
155
 
        struct ictimesync_data *timedatap;
156
 
 
157
 
        vmbus_recvpacket(channel, time_txf_buf,
158
 
                         PAGE_SIZE, &recvlen, &requestid);
159
 
 
160
 
        if (recvlen > 0) {
161
 
                DPRINT_DBG(VMBUS, "timesync packet: recvlen=%d, requestid=%lld",
162
 
                        recvlen, requestid);
163
 
 
164
 
                icmsghdrp = (struct icmsg_hdr *)&time_txf_buf[
165
 
                                sizeof(struct vmbuspipe_hdr)];
166
 
 
167
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
168
 
                        prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
169
 
                } else {
170
 
                        timedatap = (struct ictimesync_data *)&time_txf_buf[
171
 
                                sizeof(struct vmbuspipe_hdr) +
172
 
                                sizeof(struct icmsg_hdr)];
173
 
                        adj_guesttime(timedatap->parenttime, timedatap->flags);
174
 
                }
175
 
 
176
 
                icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
177
 
                        | ICMSGHDRFLAG_RESPONSE;
178
 
 
179
 
                vmbus_sendpacket(channel, time_txf_buf,
180
 
                                recvlen, requestid,
181
 
                                VmbusPacketTypeDataInBand, 0);
182
 
        }
183
 
}
184
 
 
185
 
/*
186
 
 * Heartbeat functionality.
187
 
 * Every two seconds, Hyper-V send us a heartbeat request message.
188
 
 * we respond to this message, and Hyper-V knows we are alive.
189
 
 */
190
 
static void heartbeat_onchannelcallback(void *context)
191
 
{
192
 
        struct vmbus_channel *channel = context;
193
 
        u32 recvlen;
194
 
        u64 requestid;
195
 
        struct icmsg_hdr *icmsghdrp;
196
 
        struct heartbeat_msg_data *heartbeat_msg;
197
 
 
198
 
        vmbus_recvpacket(channel, hbeat_txf_buf,
199
 
                         PAGE_SIZE, &recvlen, &requestid);
200
 
 
201
 
        if (recvlen > 0) {
202
 
                DPRINT_DBG(VMBUS, "heartbeat packet: len=%d, requestid=%lld",
203
 
                           recvlen, requestid);
204
 
 
205
 
                icmsghdrp = (struct icmsg_hdr *)&hbeat_txf_buf[
206
 
                                sizeof(struct vmbuspipe_hdr)];
207
 
 
208
 
                if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
209
 
                        prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
210
 
                } else {
211
 
                        heartbeat_msg =
212
 
                                (struct heartbeat_msg_data *)&hbeat_txf_buf[
213
 
                                        sizeof(struct vmbuspipe_hdr) +
214
 
                                        sizeof(struct icmsg_hdr)];
215
 
 
216
 
                        DPRINT_DBG(VMBUS, "heartbeat seq = %lld",
217
 
                                   heartbeat_msg->seq_num);
218
 
 
219
 
                        heartbeat_msg->seq_num += 1;
220
 
                }
221
 
 
222
 
                icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
223
 
                        | ICMSGHDRFLAG_RESPONSE;
224
 
 
225
 
                vmbus_sendpacket(channel, hbeat_txf_buf,
226
 
                                       recvlen, requestid,
227
 
                                       VmbusPacketTypeDataInBand, 0);
228
 
        }
229
 
}
230
 
 
231
 
static const struct pci_device_id __initconst
232
 
hv_utils_pci_table[] __maybe_unused = {
233
 
        { PCI_DEVICE(0x1414, 0x5353) }, /* Hyper-V emulated VGA controller */
234
 
        { 0 }
235
 
};
236
 
MODULE_DEVICE_TABLE(pci, hv_utils_pci_table);
237
 
 
238
 
 
239
 
static const struct dmi_system_id __initconst
240
 
hv_utils_dmi_table[] __maybe_unused  = {
241
 
        {
242
 
                .ident = "Hyper-V",
243
 
                .matches = {
244
 
                        DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
245
 
                        DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
246
 
                        DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
247
 
                },
248
 
        },
249
 
        { },
250
 
};
251
 
MODULE_DEVICE_TABLE(dmi, hv_utils_dmi_table);
252
 
 
253
 
 
254
 
static int __init init_hyperv_utils(void)
255
 
{
256
 
        printk(KERN_INFO "Registering HyperV Utility Driver\n");
257
 
 
258
 
        if (!dmi_check_system(hv_utils_dmi_table))
259
 
                return -ENODEV;
260
 
 
261
 
        shut_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
262
 
        time_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
263
 
        hbeat_txf_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
264
 
 
265
 
        if (!shut_txf_buf || !time_txf_buf || !hbeat_txf_buf) {
266
 
                printk(KERN_INFO
267
 
                       "Unable to allocate memory for receive buffer\n");
268
 
                kfree(shut_txf_buf);
269
 
                kfree(time_txf_buf);
270
 
                kfree(hbeat_txf_buf);
271
 
                return -ENOMEM;
272
 
        }
273
 
 
274
 
        hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
275
 
                &shutdown_onchannelcallback;
276
 
        hv_cb_utils[HV_SHUTDOWN_MSG].callback = &shutdown_onchannelcallback;
277
 
 
278
 
        hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
279
 
                &timesync_onchannelcallback;
280
 
        hv_cb_utils[HV_TIMESYNC_MSG].callback = &timesync_onchannelcallback;
281
 
 
282
 
        hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
283
 
                &heartbeat_onchannelcallback;
284
 
        hv_cb_utils[HV_HEARTBEAT_MSG].callback = &heartbeat_onchannelcallback;
285
 
 
286
 
        return 0;
287
 
}
288
 
 
289
 
static void exit_hyperv_utils(void)
290
 
{
291
 
        printk(KERN_INFO "De-Registered HyperV Utility Driver\n");
292
 
 
293
 
        hv_cb_utils[HV_SHUTDOWN_MSG].channel->onchannel_callback =
294
 
                &chn_cb_negotiate;
295
 
        hv_cb_utils[HV_SHUTDOWN_MSG].callback = &chn_cb_negotiate;
296
 
 
297
 
        hv_cb_utils[HV_TIMESYNC_MSG].channel->onchannel_callback =
298
 
                &chn_cb_negotiate;
299
 
        hv_cb_utils[HV_TIMESYNC_MSG].callback = &chn_cb_negotiate;
300
 
 
301
 
        hv_cb_utils[HV_HEARTBEAT_MSG].channel->onchannel_callback =
302
 
                &chn_cb_negotiate;
303
 
        hv_cb_utils[HV_HEARTBEAT_MSG].callback = &chn_cb_negotiate;
304
 
 
305
 
        kfree(shut_txf_buf);
306
 
        kfree(time_txf_buf);
307
 
        kfree(hbeat_txf_buf);
308
 
}
309
 
 
310
 
module_init(init_hyperv_utils);
311
 
module_exit(exit_hyperv_utils);
312
 
 
313
 
MODULE_DESCRIPTION("Hyper-V Utilities");
314
 
MODULE_VERSION(HV_DRV_VERSION);
315
 
MODULE_LICENSE("GPL");