aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2014-04-08 21:45:53 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-03 19:24:26 -0400
commitd3ba720dd58cdf6630fee4b89482c465d5ad0d0f (patch)
tree03ea0aba6f0509bf7c501dee9ae6e931634f3c4b /drivers/hv
parente4d8270e604c3202131bac607969605ac397b893 (diff)
Drivers: hv: Eliminate the channel spinlock in the callback path
By ensuring that we set the callback handler to NULL in the channel close path on the same CPU that the channel is bound to, we can eliminate this lock acquisition and release in a performance critical path. 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')
-rw-r--r--drivers/hv/channel.c16
-rw-r--r--drivers/hv/channel_mgmt.c11
-rw-r--r--drivers/hv/connection.c11
3 files changed, 23 insertions, 15 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 602ca86a6488..740edec161bb 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -471,18 +471,26 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle)
471} 471}
472EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); 472EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
473 473
474static void reset_channel_cb(void *arg)
475{
476 struct vmbus_channel *channel = arg;
477
478 channel->onchannel_callback = NULL;
479}
480
474static void vmbus_close_internal(struct vmbus_channel *channel) 481static void vmbus_close_internal(struct vmbus_channel *channel)
475{ 482{
476 struct vmbus_channel_close_channel *msg; 483 struct vmbus_channel_close_channel *msg;
477 int ret; 484 int ret;
478 unsigned long flags;
479 485
480 channel->state = CHANNEL_OPEN_STATE; 486 channel->state = CHANNEL_OPEN_STATE;
481 channel->sc_creation_callback = NULL; 487 channel->sc_creation_callback = NULL;
482 /* Stop callback and cancel the timer asap */ 488 /* Stop callback and cancel the timer asap */
483 spin_lock_irqsave(&channel->inbound_lock, flags); 489 if (channel->target_cpu != smp_processor_id())
484 channel->onchannel_callback = NULL; 490 smp_call_function_single(channel->target_cpu, reset_channel_cb,
485 spin_unlock_irqrestore(&channel->inbound_lock, flags); 491 channel, true);
492 else
493 reset_channel_cb(channel);
486 494
487 /* Send a closing message */ 495 /* Send a closing message */
488 496
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index fa920469bf10..6f7fdd9a7e77 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -365,7 +365,7 @@ static u32 next_vp;
365 * performance critical channels (IDE, SCSI and Network) will be uniformly 365 * performance critical channels (IDE, SCSI and Network) will be uniformly
366 * distributed across all available CPUs. 366 * distributed across all available CPUs.
367 */ 367 */
368static u32 get_vp_index(uuid_le *type_guid) 368static void init_vp_index(struct vmbus_channel *channel, uuid_le *type_guid)
369{ 369{
370 u32 cur_cpu; 370 u32 cur_cpu;
371 int i; 371 int i;
@@ -387,10 +387,13 @@ static u32 get_vp_index(uuid_le *type_guid)
387 * Also if the channel is not a performance critical 387 * Also if the channel is not a performance critical
388 * channel, bind it to cpu 0. 388 * channel, bind it to cpu 0.
389 */ 389 */
390 return 0; 390 channel->target_cpu = 0;
391 channel->target_vp = 0;
392 return;
391 } 393 }
392 cur_cpu = (++next_vp % max_cpus); 394 cur_cpu = (++next_vp % max_cpus);
393 return hv_context.vp_index[cur_cpu]; 395 channel->target_cpu = cur_cpu;
396 channel->target_vp = hv_context.vp_index[cur_cpu];
394} 397}
395 398
396/* 399/*
@@ -438,7 +441,7 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
438 offer->connection_id; 441 offer->connection_id;
439 } 442 }
440 443
441 newchannel->target_vp = get_vp_index(&offer->offer.if_type); 444 init_vp_index(newchannel, &offer->offer.if_type);
442 445
443 memcpy(&newchannel->offermsg, offer, 446 memcpy(&newchannel->offermsg, offer,
444 sizeof(struct vmbus_channel_offer_channel)); 447 sizeof(struct vmbus_channel_offer_channel));
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 2e7801af466e..df2363ea017f 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -277,7 +277,6 @@ struct vmbus_channel *relid2channel(u32 relid)
277static void process_chn_event(u32 relid) 277static void process_chn_event(u32 relid)
278{ 278{
279 struct vmbus_channel *channel; 279 struct vmbus_channel *channel;
280 unsigned long flags;
281 void *arg; 280 void *arg;
282 bool read_state; 281 bool read_state;
283 u32 bytes_to_read; 282 u32 bytes_to_read;
@@ -296,13 +295,12 @@ static void process_chn_event(u32 relid)
296 /* 295 /*
297 * A channel once created is persistent even when there 296 * A channel once created is persistent even when there
298 * is no driver handling the device. An unloading driver 297 * is no driver handling the device. An unloading driver
299 * sets the onchannel_callback to NULL under the 298 * sets the onchannel_callback to NULL on the same CPU
300 * protection of the channel inbound_lock. Thus, checking 299 * as where this interrupt is handled (in an interrupt context).
301 * and invoking the driver specific callback takes care of 300 * Thus, checking and invoking the driver specific callback takes
302 * orderly unloading of the driver. 301 * care of orderly unloading of the driver.
303 */ 302 */
304 303
305 spin_lock_irqsave(&channel->inbound_lock, flags);
306 if (channel->onchannel_callback != NULL) { 304 if (channel->onchannel_callback != NULL) {
307 arg = channel->channel_callback_context; 305 arg = channel->channel_callback_context;
308 read_state = channel->batched_reading; 306 read_state = channel->batched_reading;
@@ -327,7 +325,6 @@ static void process_chn_event(u32 relid)
327 pr_err("no channel callback for relid - %u\n", relid); 325 pr_err("no channel callback for relid - %u\n", relid);
328 } 326 }
329 327
330 spin_unlock_irqrestore(&channel->inbound_lock, flags);
331} 328}
332 329
333/* 330/*