]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/hv/connection.c
Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[karo-tx-linux.git] / drivers / hv / connection.c
index f2d7bf90c9fe5b319d85bf1372a1c0cec36aa91c..e84f4526eb36aaad44e8177febfaabde7efc2e81 100644 (file)
@@ -55,6 +55,9 @@ static __u32 vmbus_get_next_version(__u32 current_version)
        case (VERSION_WIN8):
                return VERSION_WIN7;
 
+       case (VERSION_WIN8_1):
+               return VERSION_WIN8;
+
        case (VERSION_WS2008):
        default:
                return VERSION_INVAL;
@@ -77,7 +80,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
        msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
        msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
        msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
-       if (version == VERSION_WIN8)
+       if (version == VERSION_WIN8_1)
                msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
 
        /*
@@ -221,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;
 
@@ -231,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
@@ -274,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;
@@ -283,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);
@@ -293,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;
@@ -324,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);
 }
 
 /*