Deleted Added
full compact
hv_connection.c (255524) hv_connection.c (282212)
1/*-
2 * Copyright (c) 2009-2012 Microsoft Corp.
3 * Copyright (c) 2012 NetApp Inc.
4 * Copyright (c) 2012 Citrix Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 31 unchanged lines hidden (view full) ---

40
41/*
42 * Globals
43 */
44hv_vmbus_connection hv_vmbus_g_connection =
45 { .connect_state = HV_DISCONNECTED,
46 .next_gpadl_handle = 0xE1E10, };
47
1/*-
2 * Copyright (c) 2009-2012 Microsoft Corp.
3 * Copyright (c) 2012 NetApp Inc.
4 * Copyright (c) 2012 Citrix Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 31 unchanged lines hidden (view full) ---

40
41/*
42 * Globals
43 */
44hv_vmbus_connection hv_vmbus_g_connection =
45 { .connect_state = HV_DISCONNECTED,
46 .next_gpadl_handle = 0xE1E10, };
47
48uint32_t hv_vmbus_protocal_version = HV_VMBUS_VERSION_WS2008;
49
50static uint32_t
51hv_vmbus_get_next_version(uint32_t current_ver)
52{
53 switch (current_ver) {
54 case (HV_VMBUS_VERSION_WIN7):
55 return(HV_VMBUS_VERSION_WS2008);
56
57 case (HV_VMBUS_VERSION_WIN8):
58 return(HV_VMBUS_VERSION_WIN7);
59
60 case (HV_VMBUS_VERSION_WIN8_1):
61 return(HV_VMBUS_VERSION_WIN8);
62
63 case (HV_VMBUS_VERSION_WS2008):
64 default:
65 return(HV_VMBUS_VERSION_INVALID);
66 }
67}
68
48/**
69/**
70 * Negotiate the highest supported hypervisor version.
71 */
72static int
73hv_vmbus_negotiate_version(hv_vmbus_channel_msg_info *msg_info,
74 uint32_t version)
75{
76 int ret = 0;
77 hv_vmbus_channel_initiate_contact *msg;
78
79 sema_init(&msg_info->wait_sema, 0, "Msg Info Sema");
80 msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg;
81
82 msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
83 msg->vmbus_version_requested = version;
84
85 msg->interrupt_page = hv_get_phys_addr(
86 hv_vmbus_g_connection.interrupt_page);
87
88 msg->monitor_page_1 = hv_get_phys_addr(
89 hv_vmbus_g_connection.monitor_pages);
90
91 msg->monitor_page_2 =
92 hv_get_phys_addr(
93 ((uint8_t *) hv_vmbus_g_connection.monitor_pages
94 + PAGE_SIZE));
95
96 /**
97 * Add to list before we send the request since we may receive the
98 * response before returning from this routine
99 */
100 mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
101
102 TAILQ_INSERT_TAIL(
103 &hv_vmbus_g_connection.channel_msg_anchor,
104 msg_info,
105 msg_list_entry);
106
107 mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
108
109 ret = hv_vmbus_post_message(
110 msg,
111 sizeof(hv_vmbus_channel_initiate_contact));
112
113 if (ret != 0) {
114 mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
115 TAILQ_REMOVE(
116 &hv_vmbus_g_connection.channel_msg_anchor,
117 msg_info,
118 msg_list_entry);
119 mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
120 return (ret);
121 }
122
123 /**
124 * Wait for the connection response
125 */
126 ret = sema_timedwait(&msg_info->wait_sema, 500); /* KYS 5 seconds */
127
128 mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
129 TAILQ_REMOVE(
130 &hv_vmbus_g_connection.channel_msg_anchor,
131 msg_info,
132 msg_list_entry);
133 mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
134
135 /**
136 * Check if successful
137 */
138 if (msg_info->response.version_response.version_supported) {
139 hv_vmbus_g_connection.connect_state = HV_CONNECTED;
140 } else {
141 ret = ECONNREFUSED;
142 }
143
144 return (ret);
145}
146
147/**
49 * Send a connect request on the partition service connection
50 */
51int
52hv_vmbus_connect(void) {
53 int ret = 0;
148 * Send a connect request on the partition service connection
149 */
150int
151hv_vmbus_connect(void) {
152 int ret = 0;
153 uint32_t version;
54 hv_vmbus_channel_msg_info* msg_info = NULL;
154 hv_vmbus_channel_msg_info* msg_info = NULL;
55 hv_vmbus_channel_initiate_contact* msg;
56
57 /**
58 * Make sure we are not connecting or connected
59 */
60 if (hv_vmbus_g_connection.connect_state != HV_DISCONNECTED) {
61 return (-1);
62 }
63

--- 5 unchanged lines hidden (view full) ---

69 sema_init(&hv_vmbus_g_connection.control_sema, 1, "control_sema");
70
71 TAILQ_INIT(&hv_vmbus_g_connection.channel_msg_anchor);
72 mtx_init(&hv_vmbus_g_connection.channel_msg_lock, "vmbus channel msg",
73 NULL, MTX_SPIN);
74
75 TAILQ_INIT(&hv_vmbus_g_connection.channel_anchor);
76 mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel",
155
156 /**
157 * Make sure we are not connecting or connected
158 */
159 if (hv_vmbus_g_connection.connect_state != HV_DISCONNECTED) {
160 return (-1);
161 }
162

--- 5 unchanged lines hidden (view full) ---

168 sema_init(&hv_vmbus_g_connection.control_sema, 1, "control_sema");
169
170 TAILQ_INIT(&hv_vmbus_g_connection.channel_msg_anchor);
171 mtx_init(&hv_vmbus_g_connection.channel_msg_lock, "vmbus channel msg",
172 NULL, MTX_SPIN);
173
174 TAILQ_INIT(&hv_vmbus_g_connection.channel_anchor);
175 mtx_init(&hv_vmbus_g_connection.channel_lock, "vmbus channel",
77 NULL, MTX_SPIN);
176 NULL, MTX_DEF);
78
79 /**
80 * Setup the vmbus event connection for channel interrupt abstraction
81 * stuff
82 */
83 hv_vmbus_g_connection.interrupt_page = contigmalloc(
84 PAGE_SIZE, M_DEVBUF,
85 M_NOWAIT | M_ZERO, 0UL,

--- 39 unchanged lines hidden (view full) ---

125 M_DEVBUF, M_NOWAIT | M_ZERO);
126 KASSERT(msg_info != NULL,
127 ("Error VMBUS: malloc failed for Initiate Contact message!"));
128 if (msg_info == NULL) {
129 ret = ENOMEM;
130 goto cleanup;
131 }
132
177
178 /**
179 * Setup the vmbus event connection for channel interrupt abstraction
180 * stuff
181 */
182 hv_vmbus_g_connection.interrupt_page = contigmalloc(
183 PAGE_SIZE, M_DEVBUF,
184 M_NOWAIT | M_ZERO, 0UL,

--- 39 unchanged lines hidden (view full) ---

224 M_DEVBUF, M_NOWAIT | M_ZERO);
225 KASSERT(msg_info != NULL,
226 ("Error VMBUS: malloc failed for Initiate Contact message!"));
227 if (msg_info == NULL) {
228 ret = ENOMEM;
229 goto cleanup;
230 }
231
133 sema_init(&msg_info->wait_sema, 0, "Msg Info Sema");
134 msg = (hv_vmbus_channel_initiate_contact*) msg_info->msg;
135
136 msg->header.message_type = HV_CHANNEL_MESSAGE_INITIATED_CONTACT;
137 msg->vmbus_version_requested = HV_VMBUS_REVISION_NUMBER;
138
139 msg->interrupt_page = hv_get_phys_addr(
140 hv_vmbus_g_connection.interrupt_page);
141
142 msg->monitor_page_1 = hv_get_phys_addr(
143 hv_vmbus_g_connection.monitor_pages);
144
145 msg->monitor_page_2 =
146 hv_get_phys_addr(
147 ((uint8_t *) hv_vmbus_g_connection.monitor_pages
148 + PAGE_SIZE));
149
150 /**
151 * Add to list before we send the request since we may receive the
152 * response before returning from this routine
232 /*
233 * Find the highest vmbus version number we can support.
153 */
234 */
154 mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
235 version = HV_VMBUS_VERSION_CURRENT;
155
236
156 TAILQ_INSERT_TAIL(
157 &hv_vmbus_g_connection.channel_msg_anchor,
158 msg_info,
159 msg_list_entry);
237 do {
238 ret = hv_vmbus_negotiate_version(msg_info, version);
239 if (ret == EWOULDBLOCK) {
240 /*
241 * We timed out.
242 */
243 goto cleanup;
244 }
160
245
161 mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
246 if (hv_vmbus_g_connection.connect_state == HV_CONNECTED)
247 break;
162
248
163 ret = hv_vmbus_post_message(
164 msg,
165 sizeof(hv_vmbus_channel_initiate_contact));
249 version = hv_vmbus_get_next_version(version);
250 } while (version != HV_VMBUS_VERSION_INVALID);
166
251
167 if (ret != 0) {
168 mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
169 TAILQ_REMOVE(
170 &hv_vmbus_g_connection.channel_msg_anchor,
171 msg_info,
172 msg_list_entry);
173 mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
174 goto cleanup;
175 }
252 hv_vmbus_protocal_version = version;
253 if (bootverbose)
254 printf("VMBUS: Portocal Version: %d.%d\n",
255 version >> 16, version & 0xFFFF);
176
256
177 /**
178 * Wait for the connection response
179 */
180 ret = sema_timedwait(&msg_info->wait_sema, 500); /* KYS 5 seconds */
181
182 mtx_lock_spin(&hv_vmbus_g_connection.channel_msg_lock);
183 TAILQ_REMOVE(
184 &hv_vmbus_g_connection.channel_msg_anchor,
185 msg_info,
186 msg_list_entry);
187 mtx_unlock_spin(&hv_vmbus_g_connection.channel_msg_lock);
188
189 /**
190 * Check if successful
191 */
192 if (msg_info->response.version_response.version_supported) {
193 hv_vmbus_g_connection.connect_state = HV_CONNECTED;
194 } else {
195 ret = ECONNREFUSED;
196 goto cleanup;
197 }
198
199 sema_destroy(&msg_info->wait_sema);
200 free(msg_info, M_DEVBUF);
201
202 return (0);
203
204 /*
205 * Cleanup after failure!
206 */

--- 74 unchanged lines hidden (view full) ---

281 hv_vmbus_channel* foundChannel = NULL;
282
283 /*
284 * TODO:
285 * Consider optimization where relids are stored in a fixed size array
286 * and channels are accessed without the need to take this lock or search
287 * the list.
288 */
257 sema_destroy(&msg_info->wait_sema);
258 free(msg_info, M_DEVBUF);
259
260 return (0);
261
262 /*
263 * Cleanup after failure!
264 */

--- 74 unchanged lines hidden (view full) ---

339 hv_vmbus_channel* foundChannel = NULL;
340
341 /*
342 * TODO:
343 * Consider optimization where relids are stored in a fixed size array
344 * and channels are accessed without the need to take this lock or search
345 * the list.
346 */
289 mtx_lock_spin(&hv_vmbus_g_connection.channel_lock);
347 mtx_lock(&hv_vmbus_g_connection.channel_lock);
290 TAILQ_FOREACH(channel,
291 &hv_vmbus_g_connection.channel_anchor, list_entry) {
292
293 if (channel->offer_msg.child_rel_id == rel_id) {
294 foundChannel = channel;
295 break;
296 }
297 }
348 TAILQ_FOREACH(channel,
349 &hv_vmbus_g_connection.channel_anchor, list_entry) {
350
351 if (channel->offer_msg.child_rel_id == rel_id) {
352 foundChannel = channel;
353 break;
354 }
355 }
298 mtx_unlock_spin(&hv_vmbus_g_connection.channel_lock);
356 mtx_unlock(&hv_vmbus_g_connection.channel_lock);
299
300 return (foundChannel);
301}
302
303/**
304 * Process a channel event notification
305 */
306static void
307VmbusProcessChannelEvent(uint32_t relid)
308{
357
358 return (foundChannel);
359}
360
361/**
362 * Process a channel event notification
363 */
364static void
365VmbusProcessChannelEvent(uint32_t relid)
366{
367 void* arg;
368 uint32_t bytes_to_read;
309 hv_vmbus_channel* channel;
369 hv_vmbus_channel* channel;
370 boolean_t is_batched_reading;
310
311 /**
312 * Find the channel based on this relid and invokes
313 * the channel callback to process the event
314 */
315
316 channel = hv_vmbus_get_channel_from_rel_id(relid);
317

--- 4 unchanged lines hidden (view full) ---

322 * To deal with the race condition where we might
323 * receive a packet while the relevant driver is
324 * being unloaded, dispatch the callback while
325 * holding the channel lock. The unloading driver
326 * will acquire the same channel lock to set the
327 * callback to NULL. This closes the window.
328 */
329
371
372 /**
373 * Find the channel based on this relid and invokes
374 * the channel callback to process the event
375 */
376
377 channel = hv_vmbus_get_channel_from_rel_id(relid);
378

--- 4 unchanged lines hidden (view full) ---

383 * To deal with the race condition where we might
384 * receive a packet while the relevant driver is
385 * being unloaded, dispatch the callback while
386 * holding the channel lock. The unloading driver
387 * will acquire the same channel lock to set the
388 * callback to NULL. This closes the window.
389 */
390
330 mtx_lock(&channel->inbound_lock);
391 /*
392 * Disable the lock due to newly added WITNESS check in r277723.
393 * Will seek other way to avoid race condition.
394 * -- whu
395 */
396 // mtx_lock(&channel->inbound_lock);
331 if (channel->on_channel_callback != NULL) {
397 if (channel->on_channel_callback != NULL) {
332 channel->on_channel_callback(channel->channel_callback_context);
398 arg = channel->channel_callback_context;
399 is_batched_reading = channel->batched_reading;
400 /*
401 * Optimize host to guest signaling by ensuring:
402 * 1. While reading the channel, we disable interrupts from
403 * host.
404 * 2. Ensure that we process all posted messages from the host
405 * before returning from this callback.
406 * 3. Once we return, enable signaling from the host. Once this
407 * state is set we check to see if additional packets are
408 * available to read. In this case we repeat the process.
409 */
410 do {
411 if (is_batched_reading)
412 hv_ring_buffer_read_begin(&channel->inbound);
413
414 channel->on_channel_callback(arg);
415
416 if (is_batched_reading)
417 bytes_to_read =
418 hv_ring_buffer_read_end(&channel->inbound);
419 else
420 bytes_to_read = 0;
421 } while (is_batched_reading && (bytes_to_read != 0));
333 }
422 }
334 mtx_unlock(&channel->inbound_lock);
423 // mtx_unlock(&channel->inbound_lock);
335}
336
424}
425
426#ifdef HV_DEBUG_INTR
427extern uint32_t hv_intr_count;
428extern uint32_t hv_vmbus_swintr_event_cpu[MAXCPU];
429extern uint32_t hv_vmbus_intr_cpu[MAXCPU];
430#endif
431
337/**
338 * Handler for events
339 */
340void
341hv_vmbus_on_events(void *arg)
342{
432/**
433 * Handler for events
434 */
435void
436hv_vmbus_on_events(void *arg)
437{
343 int dword;
344 int bit;
438 int bit;
439 int cpu;
440 int dword;
441 void *page_addr;
442 uint32_t* recv_interrupt_page = NULL;
345 int rel_id;
443 int rel_id;
346 int maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5;
444 int maxdword;
445 hv_vmbus_synic_event_flags *event;
347 /* int maxdword = PAGE_SIZE >> 3; */
348
446 /* int maxdword = PAGE_SIZE >> 3; */
447
349 /*
350 * receive size is 1/2 page and divide that by 4 bytes
351 */
448 cpu = (int)(long)arg;
449 KASSERT(cpu <= mp_maxid, ("VMBUS: hv_vmbus_on_events: "
450 "cpu out of range!"));
352
451
353 uint32_t* recv_interrupt_page =
354 hv_vmbus_g_connection.recv_interrupt_page;
452#ifdef HV_DEBUG_INTR
453 int i;
454 hv_vmbus_swintr_event_cpu[cpu]++;
455 if (hv_intr_count % 10000 == 0) {
456 printf("VMBUS: Total interrupt %d\n", hv_intr_count);
457 for (i = 0; i < mp_ncpus; i++)
458 printf("VMBUS: hw cpu[%d]: %d, event sw intr cpu[%d]: %d\n",
459 i, hv_vmbus_intr_cpu[i], i, hv_vmbus_swintr_event_cpu[i]);
460 }
461#endif
355
462
463 if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
464 (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
465 maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5;
466 /*
467 * receive size is 1/2 page and divide that by 4 bytes
468 */
469 recv_interrupt_page =
470 hv_vmbus_g_connection.recv_interrupt_page;
471 } else {
472 /*
473 * On Host with Win8 or above, the event page can be
474 * checked directly to get the id of the channel
475 * that has the pending interrupt.
476 */
477 maxdword = HV_EVENT_FLAGS_DWORD_COUNT;
478 page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
479 event = (hv_vmbus_synic_event_flags *)
480 page_addr + HV_VMBUS_MESSAGE_SINT;
481 recv_interrupt_page = event->flags32;
482 }
483
356 /*
357 * Check events
358 */
359 if (recv_interrupt_page != NULL) {
360 for (dword = 0; dword < maxdword; dword++) {
361 if (recv_interrupt_page[dword]) {
362 for (bit = 0; bit < 32; bit++) {
363 if (synch_test_and_clear_bit(bit,

--- 47 unchanged lines hidden (view full) ---

411
412 return (ret);
413}
414
415/**
416 * Send an event notification to the parent
417 */
418int
484 /*
485 * Check events
486 */
487 if (recv_interrupt_page != NULL) {
488 for (dword = 0; dword < maxdword; dword++) {
489 if (recv_interrupt_page[dword]) {
490 for (bit = 0; bit < 32; bit++) {
491 if (synch_test_and_clear_bit(bit,

--- 47 unchanged lines hidden (view full) ---

539
540 return (ret);
541}
542
543/**
544 * Send an event notification to the parent
545 */
546int
419hv_vmbus_set_event(uint32_t child_rel_id) {
547hv_vmbus_set_event(hv_vmbus_channel *channel) {
420 int ret = 0;
548 int ret = 0;
549 uint32_t child_rel_id = channel->offer_msg.child_rel_id;
421
422 /* Each uint32_t represents 32 channels */
423
424 synch_set_bit(child_rel_id & 31,
425 (((uint32_t *)hv_vmbus_g_connection.send_interrupt_page
426 + (child_rel_id >> 5))));
550
551 /* Each uint32_t represents 32 channels */
552
553 synch_set_bit(child_rel_id & 31,
554 (((uint32_t *)hv_vmbus_g_connection.send_interrupt_page
555 + (child_rel_id >> 5))));
427 ret = hv_vmbus_signal_event();
556 ret = hv_vmbus_signal_event(channel->signal_event_param);
428
429 return (ret);
430}
557
558 return (ret);
559}
431