summaryrefslogtreecommitdiffstats
path: root/drivers/hv/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hv/connection.c')
-rw-r--r--drivers/hv/connection.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 2e7801af466e..e84f4526eb36 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -224,8 +224,8 @@ cleanup:
vmbus_connection.int_page = NULL;
}
- free_pages((unsigned long)vmbus_connection.monitor_pages[0], 1);
- free_pages((unsigned long)vmbus_connection.monitor_pages[1], 1);
+ free_pages((unsigned long)vmbus_connection.monitor_pages[0], 0);
+ free_pages((unsigned long)vmbus_connection.monitor_pages[1], 0);
vmbus_connection.monitor_pages[0] = NULL;
vmbus_connection.monitor_pages[1] = NULL;
@@ -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
@@ -277,7 +299,6 @@ struct vmbus_channel *relid2channel(u32 relid)
static void process_chn_event(u32 relid)
{
struct vmbus_channel *channel;
- unsigned long flags;
void *arg;
bool read_state;
u32 bytes_to_read;
@@ -286,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);
@@ -296,13 +317,12 @@ static void process_chn_event(u32 relid)
/*
* A channel once created is persistent even when there
* is no driver handling the device. An unloading driver
- * sets the onchannel_callback to NULL under the
- * protection of the channel inbound_lock. Thus, checking
- * and invoking the driver specific callback takes care of
- * orderly unloading of the driver.
+ * sets the onchannel_callback to NULL on the same CPU
+ * as where this interrupt is handled (in an interrupt context).
+ * Thus, checking and invoking the driver specific callback takes
+ * care of orderly unloading of the driver.
*/
- spin_lock_irqsave(&channel->inbound_lock, flags);
if (channel->onchannel_callback != NULL) {
arg = channel->channel_callback_context;
read_state = channel->batched_reading;
@@ -327,7 +347,6 @@ static void process_chn_event(u32 relid)
pr_err("no channel callback for relid - %u\n", relid);
}
- spin_unlock_irqrestore(&channel->inbound_lock, flags);
}
/*