summaryrefslogtreecommitdiffstats
path: root/drivers/hv/connection.c
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2014-04-09 03:45:54 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-04 01:24:26 +0200
commit3a28fa35d6658703cd26f9c16aaea0eae06afd40 (patch)
treebcc8f07bbd9365e0a270c85af0e50ce3e1682987 /drivers/hv/connection.c
parentDrivers: hv: Eliminate the channel spinlock in the callback path (diff)
downloadlinux-3a28fa35d6658703cd26f9c16aaea0eae06afd40.tar.xz
linux-3a28fa35d6658703cd26f9c16aaea0eae06afd40.zip
Drivers: hv: vmbus: Implement per-CPU mapping of relid to channel
Currently the mapping of the relID to channel is done under the protection of a single spin lock. Starting with ws2012, each channel is bound to a specific VCPU in the guest. Use this binding to eliminate the spin lock by setting up per-cpu state for mapping relId to the channel. 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/connection.c')
-rw-r--r--drivers/hv/connection.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index df2363ea017f..7f10c151632a 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -234,6 +234,28 @@ cleanup:
return ret;
}
+/*
+ * Map the given relid to the corresponding channel based on the
+ * per-cpu list of channels that have been affinitized to this CPU.
+ * This will be used in the channel callback path as we can do this
+ * mapping in a lock-free fashion.
+ */
+static struct vmbus_channel *pcpu_relid2channel(u32 relid)
+{
+ struct vmbus_channel *channel;
+ struct vmbus_channel *found_channel = NULL;
+ int cpu = smp_processor_id();
+ struct list_head *pcpu_head = &hv_context.percpu_list[cpu];
+
+ list_for_each_entry(channel, pcpu_head, percpu_list) {
+ if (channel->offermsg.child_relid == relid) {
+ found_channel = channel;
+ break;
+ }
+ }
+
+ return found_channel;
+}
/*
* relid2channel - Get the channel object given its
@@ -285,7 +307,7 @@ static void process_chn_event(u32 relid)
* Find the channel based on this relid and invokes the
* channel callback to process the event
*/
- channel = relid2channel(relid);
+ channel = pcpu_relid2channel(relid);
if (!channel) {
pr_err("channel not found for relid - %u\n", relid);