diff options
Diffstat (limited to 'drivers/hv')
-rw-r--r-- | drivers/hv/hv.c | 34 | ||||
-rw-r--r-- | drivers/hv/hv_kvp.c | 253 | ||||
-rw-r--r-- | drivers/hv/hv_util.c | 4 | ||||
-rw-r--r-- | drivers/hv/hyperv_vmbus.h | 47 | ||||
-rw-r--r-- | drivers/hv/vmbus_drv.c | 42 |
5 files changed, 283 insertions, 97 deletions
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 86f8885aeb45..3648f8f0f368 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <linux/hyperv.h> | 28 | #include <linux/hyperv.h> |
29 | #include <linux/version.h> | ||
29 | #include <asm/hyperv.h> | 30 | #include <asm/hyperv.h> |
30 | #include "hyperv_vmbus.h" | 31 | #include "hyperv_vmbus.h" |
31 | 32 | ||
@@ -38,28 +39,6 @@ struct hv_context hv_context = { | |||
38 | }; | 39 | }; |
39 | 40 | ||
40 | /* | 41 | /* |
41 | * query_hypervisor_presence | ||
42 | * - Query the cpuid for presence of windows hypervisor | ||
43 | */ | ||
44 | static int query_hypervisor_presence(void) | ||
45 | { | ||
46 | unsigned int eax; | ||
47 | unsigned int ebx; | ||
48 | unsigned int ecx; | ||
49 | unsigned int edx; | ||
50 | unsigned int op; | ||
51 | |||
52 | eax = 0; | ||
53 | ebx = 0; | ||
54 | ecx = 0; | ||
55 | edx = 0; | ||
56 | op = HVCPUID_VERSION_FEATURES; | ||
57 | cpuid(op, &eax, &ebx, &ecx, &edx); | ||
58 | |||
59 | return ecx & HV_PRESENT_BIT; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * query_hypervisor_info - Get version info of the windows hypervisor | 42 | * query_hypervisor_info - Get version info of the windows hypervisor |
64 | */ | 43 | */ |
65 | static int query_hypervisor_info(void) | 44 | static int query_hypervisor_info(void) |
@@ -159,14 +138,13 @@ int hv_init(void) | |||
159 | memset(hv_context.synic_message_page, 0, | 138 | memset(hv_context.synic_message_page, 0, |
160 | sizeof(void *) * NR_CPUS); | 139 | sizeof(void *) * NR_CPUS); |
161 | 140 | ||
162 | if (!query_hypervisor_presence()) | ||
163 | goto cleanup; | ||
164 | |||
165 | max_leaf = query_hypervisor_info(); | 141 | max_leaf = query_hypervisor_info(); |
166 | 142 | ||
167 | /* Write our OS info */ | 143 | /* |
168 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID); | 144 | * Write our OS ID. |
169 | hv_context.guestid = HV_LINUX_GUEST_ID; | 145 | */ |
146 | hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0); | ||
147 | wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid); | ||
170 | 148 | ||
171 | /* See if the hypercall page is already set */ | 149 | /* See if the hypercall page is already set */ |
172 | rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); | 150 | rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); |
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 0012eed6d872..ed50e9e83c61 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -48,13 +48,24 @@ static struct { | |||
48 | void *kvp_context; /* for the channel callback */ | 48 | void *kvp_context; /* for the channel callback */ |
49 | } kvp_transaction; | 49 | } kvp_transaction; |
50 | 50 | ||
51 | /* | ||
52 | * Before we can accept KVP messages from the host, we need | ||
53 | * to handshake with the user level daemon. This state tracks | ||
54 | * if we are in the handshake phase. | ||
55 | */ | ||
56 | static bool in_hand_shake = true; | ||
57 | |||
58 | /* | ||
59 | * This state maintains the version number registered by the daemon. | ||
60 | */ | ||
61 | static int dm_reg_value; | ||
62 | |||
51 | static void kvp_send_key(struct work_struct *dummy); | 63 | static void kvp_send_key(struct work_struct *dummy); |
52 | 64 | ||
53 | #define TIMEOUT_FIRED 1 | ||
54 | 65 | ||
55 | static void kvp_respond_to_host(char *key, char *value, int error); | 66 | static void kvp_respond_to_host(struct hv_kvp_msg *msg, int error); |
56 | static void kvp_work_func(struct work_struct *dummy); | 67 | static void kvp_work_func(struct work_struct *dummy); |
57 | static void kvp_register(void); | 68 | static void kvp_register(int); |
58 | 69 | ||
59 | static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func); | 70 | static DECLARE_DELAYED_WORK(kvp_work, kvp_work_func); |
60 | static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); | 71 | static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); |
@@ -68,7 +79,7 @@ static u8 *recv_buffer; | |||
68 | */ | 79 | */ |
69 | 80 | ||
70 | static void | 81 | static void |
71 | kvp_register(void) | 82 | kvp_register(int reg_value) |
72 | { | 83 | { |
73 | 84 | ||
74 | struct cn_msg *msg; | 85 | struct cn_msg *msg; |
@@ -83,7 +94,7 @@ kvp_register(void) | |||
83 | msg->id.idx = CN_KVP_IDX; | 94 | msg->id.idx = CN_KVP_IDX; |
84 | msg->id.val = CN_KVP_VAL; | 95 | msg->id.val = CN_KVP_VAL; |
85 | 96 | ||
86 | kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER; | 97 | kvp_msg->kvp_hdr.operation = reg_value; |
87 | strcpy(version, HV_DRV_VERSION); | 98 | strcpy(version, HV_DRV_VERSION); |
88 | msg->len = sizeof(struct hv_kvp_msg); | 99 | msg->len = sizeof(struct hv_kvp_msg); |
89 | cn_netlink_send(msg, 0, GFP_ATOMIC); | 100 | cn_netlink_send(msg, 0, GFP_ATOMIC); |
@@ -97,9 +108,43 @@ kvp_work_func(struct work_struct *dummy) | |||
97 | * If the timer fires, the user-mode component has not responded; | 108 | * If the timer fires, the user-mode component has not responded; |
98 | * process the pending transaction. | 109 | * process the pending transaction. |
99 | */ | 110 | */ |
100 | kvp_respond_to_host("Unknown key", "Guest timed out", TIMEOUT_FIRED); | 111 | kvp_respond_to_host(NULL, HV_E_FAIL); |
112 | } | ||
113 | |||
114 | static int kvp_handle_handshake(struct hv_kvp_msg *msg) | ||
115 | { | ||
116 | int ret = 1; | ||
117 | |||
118 | switch (msg->kvp_hdr.operation) { | ||
119 | case KVP_OP_REGISTER: | ||
120 | dm_reg_value = KVP_OP_REGISTER; | ||
121 | pr_info("KVP: IP injection functionality not available\n"); | ||
122 | pr_info("KVP: Upgrade the KVP daemon\n"); | ||
123 | break; | ||
124 | case KVP_OP_REGISTER1: | ||
125 | dm_reg_value = KVP_OP_REGISTER1; | ||
126 | break; | ||
127 | default: | ||
128 | pr_info("KVP: incompatible daemon\n"); | ||
129 | pr_info("KVP: KVP version: %d, Daemon version: %d\n", | ||
130 | KVP_OP_REGISTER1, msg->kvp_hdr.operation); | ||
131 | ret = 0; | ||
132 | } | ||
133 | |||
134 | if (ret) { | ||
135 | /* | ||
136 | * We have a compatible daemon; complete the handshake. | ||
137 | */ | ||
138 | pr_info("KVP: user-mode registering done.\n"); | ||
139 | kvp_register(dm_reg_value); | ||
140 | kvp_transaction.active = false; | ||
141 | if (kvp_transaction.kvp_context) | ||
142 | hv_kvp_onchannelcallback(kvp_transaction.kvp_context); | ||
143 | } | ||
144 | return ret; | ||
101 | } | 145 | } |
102 | 146 | ||
147 | |||
103 | /* | 148 | /* |
104 | * Callback when data is received from user mode. | 149 | * Callback when data is received from user mode. |
105 | */ | 150 | */ |
@@ -109,29 +154,165 @@ kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
109 | { | 154 | { |
110 | struct hv_kvp_msg *message; | 155 | struct hv_kvp_msg *message; |
111 | struct hv_kvp_msg_enumerate *data; | 156 | struct hv_kvp_msg_enumerate *data; |
157 | int error = 0; | ||
112 | 158 | ||
113 | message = (struct hv_kvp_msg *)msg->data; | 159 | message = (struct hv_kvp_msg *)msg->data; |
114 | switch (message->kvp_hdr.operation) { | 160 | |
161 | /* | ||
162 | * If we are negotiating the version information | ||
163 | * with the daemon; handle that first. | ||
164 | */ | ||
165 | |||
166 | if (in_hand_shake) { | ||
167 | if (kvp_handle_handshake(message)) | ||
168 | in_hand_shake = false; | ||
169 | return; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * Based on the version of the daemon, we propagate errors from the | ||
174 | * daemon differently. | ||
175 | */ | ||
176 | |||
177 | data = &message->body.kvp_enum_data; | ||
178 | |||
179 | switch (dm_reg_value) { | ||
115 | case KVP_OP_REGISTER: | 180 | case KVP_OP_REGISTER: |
116 | pr_info("KVP: user-mode registering done.\n"); | 181 | /* |
117 | kvp_register(); | 182 | * Null string is used to pass back error condition. |
118 | kvp_transaction.active = false; | 183 | */ |
119 | hv_kvp_onchannelcallback(kvp_transaction.kvp_context); | 184 | if (data->data.key[0] == 0) |
185 | error = HV_S_CONT; | ||
120 | break; | 186 | break; |
121 | 187 | ||
122 | default: | 188 | case KVP_OP_REGISTER1: |
123 | data = &message->body.kvp_enum_data; | ||
124 | /* | 189 | /* |
125 | * Complete the transaction by forwarding the key value | 190 | * We use the message header information from |
126 | * to the host. But first, cancel the timeout. | 191 | * the user level daemon to transmit errors. |
127 | */ | 192 | */ |
128 | if (cancel_delayed_work_sync(&kvp_work)) | 193 | error = message->error; |
129 | kvp_respond_to_host(data->data.key, | 194 | break; |
130 | data->data.value, | 195 | } |
131 | !strlen(data->data.key)); | 196 | |
197 | /* | ||
198 | * Complete the transaction by forwarding the key value | ||
199 | * to the host. But first, cancel the timeout. | ||
200 | */ | ||
201 | if (cancel_delayed_work_sync(&kvp_work)) | ||
202 | kvp_respond_to_host(message, error); | ||
203 | } | ||
204 | |||
205 | |||
206 | static int process_ob_ipinfo(void *in_msg, void *out_msg, int op) | ||
207 | { | ||
208 | struct hv_kvp_msg *in = in_msg; | ||
209 | struct hv_kvp_ip_msg *out = out_msg; | ||
210 | int len; | ||
211 | |||
212 | switch (op) { | ||
213 | case KVP_OP_GET_IP_INFO: | ||
214 | /* | ||
215 | * Transform all parameters into utf16 encoding. | ||
216 | */ | ||
217 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.ip_addr, | ||
218 | strlen((char *)in->body.kvp_ip_val.ip_addr), | ||
219 | UTF16_HOST_ENDIAN, | ||
220 | (wchar_t *)out->kvp_ip_val.ip_addr, | ||
221 | MAX_IP_ADDR_SIZE); | ||
222 | if (len < 0) | ||
223 | return len; | ||
224 | |||
225 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.sub_net, | ||
226 | strlen((char *)in->body.kvp_ip_val.sub_net), | ||
227 | UTF16_HOST_ENDIAN, | ||
228 | (wchar_t *)out->kvp_ip_val.sub_net, | ||
229 | MAX_IP_ADDR_SIZE); | ||
230 | if (len < 0) | ||
231 | return len; | ||
232 | |||
233 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.gate_way, | ||
234 | strlen((char *)in->body.kvp_ip_val.gate_way), | ||
235 | UTF16_HOST_ENDIAN, | ||
236 | (wchar_t *)out->kvp_ip_val.gate_way, | ||
237 | MAX_GATEWAY_SIZE); | ||
238 | if (len < 0) | ||
239 | return len; | ||
240 | |||
241 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.dns_addr, | ||
242 | strlen((char *)in->body.kvp_ip_val.dns_addr), | ||
243 | UTF16_HOST_ENDIAN, | ||
244 | (wchar_t *)out->kvp_ip_val.dns_addr, | ||
245 | MAX_IP_ADDR_SIZE); | ||
246 | if (len < 0) | ||
247 | return len; | ||
248 | |||
249 | len = utf8s_to_utf16s((char *)in->body.kvp_ip_val.adapter_id, | ||
250 | strlen((char *)in->body.kvp_ip_val.adapter_id), | ||
251 | UTF16_HOST_ENDIAN, | ||
252 | (wchar_t *)out->kvp_ip_val.adapter_id, | ||
253 | MAX_IP_ADDR_SIZE); | ||
254 | if (len < 0) | ||
255 | return len; | ||
256 | |||
257 | out->kvp_ip_val.dhcp_enabled = | ||
258 | in->body.kvp_ip_val.dhcp_enabled; | ||
259 | out->kvp_ip_val.addr_family = | ||
260 | in->body.kvp_ip_val.addr_family; | ||
261 | } | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static void process_ib_ipinfo(void *in_msg, void *out_msg, int op) | ||
267 | { | ||
268 | struct hv_kvp_ip_msg *in = in_msg; | ||
269 | struct hv_kvp_msg *out = out_msg; | ||
270 | |||
271 | switch (op) { | ||
272 | case KVP_OP_SET_IP_INFO: | ||
273 | /* | ||
274 | * Transform all parameters into utf8 encoding. | ||
275 | */ | ||
276 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.ip_addr, | ||
277 | MAX_IP_ADDR_SIZE, | ||
278 | UTF16_LITTLE_ENDIAN, | ||
279 | (__u8 *)out->body.kvp_ip_val.ip_addr, | ||
280 | MAX_IP_ADDR_SIZE); | ||
281 | |||
282 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.sub_net, | ||
283 | MAX_IP_ADDR_SIZE, | ||
284 | UTF16_LITTLE_ENDIAN, | ||
285 | (__u8 *)out->body.kvp_ip_val.sub_net, | ||
286 | MAX_IP_ADDR_SIZE); | ||
287 | |||
288 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.gate_way, | ||
289 | MAX_GATEWAY_SIZE, | ||
290 | UTF16_LITTLE_ENDIAN, | ||
291 | (__u8 *)out->body.kvp_ip_val.gate_way, | ||
292 | MAX_GATEWAY_SIZE); | ||
293 | |||
294 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.dns_addr, | ||
295 | MAX_IP_ADDR_SIZE, | ||
296 | UTF16_LITTLE_ENDIAN, | ||
297 | (__u8 *)out->body.kvp_ip_val.dns_addr, | ||
298 | MAX_IP_ADDR_SIZE); | ||
299 | |||
300 | out->body.kvp_ip_val.dhcp_enabled = in->kvp_ip_val.dhcp_enabled; | ||
301 | |||
302 | default: | ||
303 | utf16s_to_utf8s((wchar_t *)in->kvp_ip_val.adapter_id, | ||
304 | MAX_ADAPTER_ID_SIZE, | ||
305 | UTF16_LITTLE_ENDIAN, | ||
306 | (__u8 *)out->body.kvp_ip_val.adapter_id, | ||
307 | MAX_ADAPTER_ID_SIZE); | ||
308 | |||
309 | out->body.kvp_ip_val.addr_family = in->kvp_ip_val.addr_family; | ||
132 | } | 310 | } |
133 | } | 311 | } |
134 | 312 | ||
313 | |||
314 | |||
315 | |||
135 | static void | 316 | static void |
136 | kvp_send_key(struct work_struct *dummy) | 317 | kvp_send_key(struct work_struct *dummy) |
137 | { | 318 | { |
@@ -167,6 +348,12 @@ kvp_send_key(struct work_struct *dummy) | |||
167 | */ | 348 | */ |
168 | 349 | ||
169 | switch (message->kvp_hdr.operation) { | 350 | switch (message->kvp_hdr.operation) { |
351 | case KVP_OP_SET_IP_INFO: | ||
352 | process_ib_ipinfo(in_msg, message, KVP_OP_SET_IP_INFO); | ||
353 | break; | ||
354 | case KVP_OP_GET_IP_INFO: | ||
355 | process_ib_ipinfo(in_msg, message, KVP_OP_GET_IP_INFO); | ||
356 | break; | ||
170 | case KVP_OP_SET: | 357 | case KVP_OP_SET: |
171 | switch (in_msg->body.kvp_set.data.value_type) { | 358 | switch (in_msg->body.kvp_set.data.value_type) { |
172 | case REG_SZ: | 359 | case REG_SZ: |
@@ -243,17 +430,19 @@ kvp_send_key(struct work_struct *dummy) | |||
243 | */ | 430 | */ |
244 | 431 | ||
245 | static void | 432 | static void |
246 | kvp_respond_to_host(char *key, char *value, int error) | 433 | kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error) |
247 | { | 434 | { |
248 | struct hv_kvp_msg *kvp_msg; | 435 | struct hv_kvp_msg *kvp_msg; |
249 | struct hv_kvp_exchg_msg_value *kvp_data; | 436 | struct hv_kvp_exchg_msg_value *kvp_data; |
250 | char *key_name; | 437 | char *key_name; |
438 | char *value; | ||
251 | struct icmsg_hdr *icmsghdrp; | 439 | struct icmsg_hdr *icmsghdrp; |
252 | int keylen = 0; | 440 | int keylen = 0; |
253 | int valuelen = 0; | 441 | int valuelen = 0; |
254 | u32 buf_len; | 442 | u32 buf_len; |
255 | struct vmbus_channel *channel; | 443 | struct vmbus_channel *channel; |
256 | u64 req_id; | 444 | u64 req_id; |
445 | int ret; | ||
257 | 446 | ||
258 | /* | 447 | /* |
259 | * If a transaction is not active; log and return. | 448 | * If a transaction is not active; log and return. |
@@ -287,6 +476,7 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
287 | */ | 476 | */ |
288 | return; | 477 | return; |
289 | 478 | ||
479 | icmsghdrp->status = error; | ||
290 | 480 | ||
291 | /* | 481 | /* |
292 | * If the error parameter is set, terminate the host's enumeration | 482 | * If the error parameter is set, terminate the host's enumeration |
@@ -294,20 +484,27 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
294 | */ | 484 | */ |
295 | if (error) { | 485 | if (error) { |
296 | /* | 486 | /* |
297 | * Something failed or the we have timedout; | 487 | * Something failed or we have timedout; |
298 | * terminate the current host-side iteration. | 488 | * terminate the current host-side iteration. |
299 | */ | 489 | */ |
300 | icmsghdrp->status = HV_S_CONT; | ||
301 | goto response_done; | 490 | goto response_done; |
302 | } | 491 | } |
303 | 492 | ||
304 | icmsghdrp->status = HV_S_OK; | ||
305 | |||
306 | kvp_msg = (struct hv_kvp_msg *) | 493 | kvp_msg = (struct hv_kvp_msg *) |
307 | &recv_buffer[sizeof(struct vmbuspipe_hdr) + | 494 | &recv_buffer[sizeof(struct vmbuspipe_hdr) + |
308 | sizeof(struct icmsg_hdr)]; | 495 | sizeof(struct icmsg_hdr)]; |
309 | 496 | ||
310 | switch (kvp_transaction.kvp_msg->kvp_hdr.operation) { | 497 | switch (kvp_transaction.kvp_msg->kvp_hdr.operation) { |
498 | case KVP_OP_GET_IP_INFO: | ||
499 | ret = process_ob_ipinfo(msg_to_host, | ||
500 | (struct hv_kvp_ip_msg *)kvp_msg, | ||
501 | KVP_OP_GET_IP_INFO); | ||
502 | if (ret < 0) | ||
503 | icmsghdrp->status = HV_E_FAIL; | ||
504 | |||
505 | goto response_done; | ||
506 | case KVP_OP_SET_IP_INFO: | ||
507 | goto response_done; | ||
311 | case KVP_OP_GET: | 508 | case KVP_OP_GET: |
312 | kvp_data = &kvp_msg->body.kvp_get.data; | 509 | kvp_data = &kvp_msg->body.kvp_get.data; |
313 | goto copy_value; | 510 | goto copy_value; |
@@ -321,7 +518,7 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
321 | } | 518 | } |
322 | 519 | ||
323 | kvp_data = &kvp_msg->body.kvp_enum_data.data; | 520 | kvp_data = &kvp_msg->body.kvp_enum_data.data; |
324 | key_name = key; | 521 | key_name = msg_to_host->body.kvp_enum_data.data.key; |
325 | 522 | ||
326 | /* | 523 | /* |
327 | * The windows host expects the key/value pair to be encoded | 524 | * The windows host expects the key/value pair to be encoded |
@@ -335,6 +532,7 @@ kvp_respond_to_host(char *key, char *value, int error) | |||
335 | kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */ | 532 | kvp_data->key_size = 2*(keylen + 1); /* utf16 encoding */ |
336 | 533 | ||
337 | copy_value: | 534 | copy_value: |
535 | value = msg_to_host->body.kvp_enum_data.data.value; | ||
338 | valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, | 536 | valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, |
339 | (wchar_t *) kvp_data->value, | 537 | (wchar_t *) kvp_data->value, |
340 | (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2); | 538 | (HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2) - 2); |
@@ -387,7 +585,8 @@ void hv_kvp_onchannelcallback(void *context) | |||
387 | return; | 585 | return; |
388 | } | 586 | } |
389 | 587 | ||
390 | vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE, &recvlen, &requestid); | 588 | vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, |
589 | &requestid); | ||
391 | 590 | ||
392 | if (recvlen > 0) { | 591 | if (recvlen > 0) { |
393 | icmsghdrp = (struct icmsg_hdr *)&recv_buffer[ | 592 | icmsghdrp = (struct icmsg_hdr *)&recv_buffer[ |
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index d3ac6a40118b..a0667de7a04c 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c | |||
@@ -263,7 +263,7 @@ static int util_probe(struct hv_device *dev, | |||
263 | (struct hv_util_service *)dev_id->driver_data; | 263 | (struct hv_util_service *)dev_id->driver_data; |
264 | int ret; | 264 | int ret; |
265 | 265 | ||
266 | srv->recv_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); | 266 | srv->recv_buffer = kmalloc(PAGE_SIZE * 2, GFP_KERNEL); |
267 | if (!srv->recv_buffer) | 267 | if (!srv->recv_buffer) |
268 | return -ENOMEM; | 268 | return -ENOMEM; |
269 | if (srv->util_init) { | 269 | if (srv->util_init) { |
@@ -274,7 +274,7 @@ static int util_probe(struct hv_device *dev, | |||
274 | } | 274 | } |
275 | } | 275 | } |
276 | 276 | ||
277 | ret = vmbus_open(dev->channel, 2 * PAGE_SIZE, 2 * PAGE_SIZE, NULL, 0, | 277 | ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0, |
278 | srv->util_cb, dev->channel); | 278 | srv->util_cb, dev->channel); |
279 | if (ret) | 279 | if (ret) |
280 | goto error; | 280 | goto error; |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 0614ff3a7d7e..d8d1fadb398a 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
@@ -410,10 +410,49 @@ enum { | |||
410 | 410 | ||
411 | #define HV_PRESENT_BIT 0x80000000 | 411 | #define HV_PRESENT_BIT 0x80000000 |
412 | 412 | ||
413 | #define HV_LINUX_GUEST_ID_LO 0x00000000 | 413 | /* |
414 | #define HV_LINUX_GUEST_ID_HI 2976579765 | 414 | * The guest OS needs to register the guest ID with the hypervisor. |
415 | #define HV_LINUX_GUEST_ID (((u64)HV_LINUX_GUEST_ID_HI << 32) | \ | 415 | * The guest ID is a 64 bit entity and the structure of this ID is |
416 | HV_LINUX_GUEST_ID_LO) | 416 | * specified in the Hyper-V specification: |
417 | * | ||
418 | * http://msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx | ||
419 | * | ||
420 | * While the current guideline does not specify how Linux guest ID(s) | ||
421 | * need to be generated, our plan is to publish the guidelines for | ||
422 | * Linux and other guest operating systems that currently are hosted | ||
423 | * on Hyper-V. The implementation here conforms to this yet | ||
424 | * unpublished guidelines. | ||
425 | * | ||
426 | * | ||
427 | * Bit(s) | ||
428 | * 63 - Indicates if the OS is Open Source or not; 1 is Open Source | ||
429 | * 62:56 - Os Type; Linux is 0x100 | ||
430 | * 55:48 - Distro specific identification | ||
431 | * 47:16 - Linux kernel version number | ||
432 | * 15:0 - Distro specific identification | ||
433 | * | ||
434 | * | ||
435 | */ | ||
436 | |||
437 | #define HV_LINUX_VENDOR_ID 0x8100 | ||
438 | |||
439 | /* | ||
440 | * Generate the guest ID based on the guideline described above. | ||
441 | */ | ||
442 | |||
443 | static inline __u64 generate_guest_id(__u8 d_info1, __u32 kernel_version, | ||
444 | __u16 d_info2) | ||
445 | { | ||
446 | __u64 guest_id = 0; | ||
447 | |||
448 | guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48); | ||
449 | guest_id |= (((__u64)(d_info1)) << 48); | ||
450 | guest_id |= (((__u64)(kernel_version)) << 16); | ||
451 | guest_id |= ((__u64)(d_info2)); | ||
452 | |||
453 | return guest_id; | ||
454 | } | ||
455 | |||
417 | 456 | ||
418 | #define HV_CPU_POWER_MANAGEMENT (1 << 0) | 457 | #define HV_CPU_POWER_MANAGEMENT (1 << 0) |
419 | #define HV_RECOMMENDATIONS_MAX 4 | 458 | #define HV_RECOMMENDATIONS_MAX 4 |
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 4748086eaaf2..8e1a9ec53003 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/completion.h> | 34 | #include <linux/completion.h> |
35 | #include <linux/hyperv.h> | 35 | #include <linux/hyperv.h> |
36 | #include <asm/hyperv.h> | 36 | #include <asm/hyperv.h> |
37 | #include <asm/hypervisor.h> | ||
37 | #include "hyperv_vmbus.h" | 38 | #include "hyperv_vmbus.h" |
38 | 39 | ||
39 | 40 | ||
@@ -146,43 +147,9 @@ static ssize_t vmbus_show_device_attr(struct device *dev, | |||
146 | get_channel_info(hv_dev, device_info); | 147 | get_channel_info(hv_dev, device_info); |
147 | 148 | ||
148 | if (!strcmp(dev_attr->attr.name, "class_id")) { | 149 | if (!strcmp(dev_attr->attr.name, "class_id")) { |
149 | ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-" | 150 | ret = sprintf(buf, "{%pUl}\n", device_info->chn_type.b); |
150 | "%02x%02x%02x%02x%02x%02x%02x%02x}\n", | ||
151 | device_info->chn_type.b[3], | ||
152 | device_info->chn_type.b[2], | ||
153 | device_info->chn_type.b[1], | ||
154 | device_info->chn_type.b[0], | ||
155 | device_info->chn_type.b[5], | ||
156 | device_info->chn_type.b[4], | ||
157 | device_info->chn_type.b[7], | ||
158 | device_info->chn_type.b[6], | ||
159 | device_info->chn_type.b[8], | ||
160 | device_info->chn_type.b[9], | ||
161 | device_info->chn_type.b[10], | ||
162 | device_info->chn_type.b[11], | ||
163 | device_info->chn_type.b[12], | ||
164 | device_info->chn_type.b[13], | ||
165 | device_info->chn_type.b[14], | ||
166 | device_info->chn_type.b[15]); | ||
167 | } else if (!strcmp(dev_attr->attr.name, "device_id")) { | 151 | } else if (!strcmp(dev_attr->attr.name, "device_id")) { |
168 | ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-" | 152 | ret = sprintf(buf, "{%pUl}\n", device_info->chn_instance.b); |
169 | "%02x%02x%02x%02x%02x%02x%02x%02x}\n", | ||
170 | device_info->chn_instance.b[3], | ||
171 | device_info->chn_instance.b[2], | ||
172 | device_info->chn_instance.b[1], | ||
173 | device_info->chn_instance.b[0], | ||
174 | device_info->chn_instance.b[5], | ||
175 | device_info->chn_instance.b[4], | ||
176 | device_info->chn_instance.b[7], | ||
177 | device_info->chn_instance.b[6], | ||
178 | device_info->chn_instance.b[8], | ||
179 | device_info->chn_instance.b[9], | ||
180 | device_info->chn_instance.b[10], | ||
181 | device_info->chn_instance.b[11], | ||
182 | device_info->chn_instance.b[12], | ||
183 | device_info->chn_instance.b[13], | ||
184 | device_info->chn_instance.b[14], | ||
185 | device_info->chn_instance.b[15]); | ||
186 | } else if (!strcmp(dev_attr->attr.name, "modalias")) { | 153 | } else if (!strcmp(dev_attr->attr.name, "modalias")) { |
187 | print_alias_name(hv_dev, alias_name); | 154 | print_alias_name(hv_dev, alias_name); |
188 | ret = sprintf(buf, "vmbus:%s\n", alias_name); | 155 | ret = sprintf(buf, "vmbus:%s\n", alias_name); |
@@ -757,6 +724,9 @@ static int __init hv_acpi_init(void) | |||
757 | { | 724 | { |
758 | int ret, t; | 725 | int ret, t; |
759 | 726 | ||
727 | if (x86_hyper != &x86_hyper_ms_hyperv) | ||
728 | return -ENODEV; | ||
729 | |||
760 | init_completion(&probe_event); | 730 | init_completion(&probe_event); |
761 | 731 | ||
762 | /* | 732 | /* |