aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv/channel.c
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2013-05-23 15:02:32 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-03 17:09:14 -0400
commite68d2971d26577b932a16333ce165af98a96e068 (patch)
tree641b8143d41993366c4d0d0b6546a1695acba83b /drivers/hv/channel.c
parent8d7bda51888d14c07cbebacc5a10be776477bb63 (diff)
Drivers: hv: vmbus: Implement multi-channel support
Starting with Win8, the host supports multiple sub-channels for a given device. As in the past, the initial channel offer specifies the device and is associated with both the type and the instance GUIDs. For performance critical devices, the host may support multiple sub-channels. The sub-channels share the same type and instance GUID as the primary channel. The number of sub-channels offerrred to the guest depends on the number of virtual CPUs assigned to the guest. The guest can request the creation of these sub-channels and once created and opened, the guest can distribute the traffic across all the channels (the primary and the sub-channels). A request sent on a sub-channel will have the response delivered on the same sub-channel. At channel (sub-channel) creation we bind the channel interrupt to a CPU and with this sub-channel support we will be able to spread the interrupt load of a given device across all available CPUs. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/channel.c')
-rw-r--r--drivers/hv/channel.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 0b122f8c7005..6de6c98ce6eb 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -116,6 +116,15 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
116 unsigned long flags; 116 unsigned long flags;
117 int ret, t, err = 0; 117 int ret, t, err = 0;
118 118
119 spin_lock_irqsave(&newchannel->sc_lock, flags);
120 if (newchannel->state == CHANNEL_OPEN_STATE) {
121 newchannel->state = CHANNEL_OPENING_STATE;
122 } else {
123 spin_unlock_irqrestore(&newchannel->sc_lock, flags);
124 return -EINVAL;
125 }
126 spin_unlock_irqrestore(&newchannel->sc_lock, flags);
127
119 newchannel->onchannel_callback = onchannelcallback; 128 newchannel->onchannel_callback = onchannelcallback;
120 newchannel->channel_callback_context = context; 129 newchannel->channel_callback_context = context;
121 130
@@ -216,6 +225,9 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
216 list_del(&open_info->msglistentry); 225 list_del(&open_info->msglistentry);
217 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 226 spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
218 227
228 if (err == 0)
229 newchannel->state = CHANNEL_OPENED_STATE;
230
219 kfree(open_info); 231 kfree(open_info);
220 return err; 232 return err;
221 233
@@ -500,15 +512,14 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
500} 512}
501EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); 513EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
502 514
503/* 515static void vmbus_close_internal(struct vmbus_channel *channel)
504 * vmbus_close - Close the specified channel
505 */
506void vmbus_close(struct vmbus_channel *channel)
507{ 516{
508 struct vmbus_channel_close_channel *msg; 517 struct vmbus_channel_close_channel *msg;
509 int ret; 518 int ret;
510 unsigned long flags; 519 unsigned long flags;
511 520
521 channel->state = CHANNEL_OPEN_STATE;
522 channel->sc_creation_callback = NULL;
512 /* Stop callback and cancel the timer asap */ 523 /* Stop callback and cancel the timer asap */
513 spin_lock_irqsave(&channel->inbound_lock, flags); 524 spin_lock_irqsave(&channel->inbound_lock, flags);
514 channel->onchannel_callback = NULL; 525 channel->onchannel_callback = NULL;
@@ -538,6 +549,37 @@ void vmbus_close(struct vmbus_channel *channel)
538 549
539 550
540} 551}
552
553/*
554 * vmbus_close - Close the specified channel
555 */
556void vmbus_close(struct vmbus_channel *channel)
557{
558 struct list_head *cur, *tmp;
559 struct vmbus_channel *cur_channel;
560
561 if (channel->primary_channel != NULL) {
562 /*
563 * We will only close sub-channels when
564 * the primary is closed.
565 */
566 return;
567 }
568 /*
569 * Close all the sub-channels first and then close the
570 * primary channel.
571 */
572 list_for_each_safe(cur, tmp, &channel->sc_list) {
573 cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
574 if (cur_channel->state != CHANNEL_OPENED_STATE)
575 continue;
576 vmbus_close_internal(cur_channel);
577 }
578 /*
579 * Now close the primary.
580 */
581 vmbus_close_internal(channel);
582}
541EXPORT_SYMBOL_GPL(vmbus_close); 583EXPORT_SYMBOL_GPL(vmbus_close);
542 584
543/** 585/**