Merge tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[firefly-linux-kernel-4.4.55.git] / drivers / hv / channel_mgmt.c
index 0df75908200e034044ee36fa3fb5403a39fc5efd..bbff5f200bef7a7b070abec6c0f7c202f335159c 100644 (file)
@@ -48,30 +48,39 @@ struct vmbus_channel_message_table_entry {
  * @negop is of type &struct icmsg_negotiate.
  * Set up and fill in default negotiate response message.
  *
- * The max_fw_version specifies the maximum framework version that
- * we can support and max _srv_version specifies the maximum service
- * version we can support. A special value MAX_SRV_VER can be
- * specified to indicate that we can handle the maximum version
- * exposed by the host.
+ * The fw_version specifies the  framework version that
+ * we can support and srv_version specifies the service
+ * version we can support.
  *
  * Mainly used by Hyper-V drivers.
  */
-void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
+bool vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
                                struct icmsg_negotiate *negop, u8 *buf,
-                               int max_fw_version, int max_srv_version)
+                               int fw_version, int srv_version)
 {
-       int icframe_vercnt;
-       int icmsg_vercnt;
+       int icframe_major, icframe_minor;
+       int icmsg_major, icmsg_minor;
+       int fw_major, fw_minor;
+       int srv_major, srv_minor;
        int i;
+       bool found_match = false;
 
        icmsghdrp->icmsgsize = 0x10;
+       fw_major = (fw_version >> 16);
+       fw_minor = (fw_version & 0xFFFF);
+
+       srv_major = (srv_version >> 16);
+       srv_minor = (srv_version & 0xFFFF);
 
        negop = (struct icmsg_negotiate *)&buf[
                sizeof(struct vmbuspipe_hdr) +
                sizeof(struct icmsg_hdr)];
 
-       icframe_vercnt = negop->icframe_vercnt;
-       icmsg_vercnt = negop->icmsg_vercnt;
+       icframe_major = negop->icframe_vercnt;
+       icframe_minor = 0;
+
+       icmsg_major = negop->icmsg_vercnt;
+       icmsg_minor = 0;
 
        /*
         * Select the framework version number we will
@@ -79,26 +88,48 @@ void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
         */
 
        for (i = 0; i < negop->icframe_vercnt; i++) {
-               if (negop->icversion_data[i].major <= max_fw_version)
-                       icframe_vercnt = negop->icversion_data[i].major;
+               if ((negop->icversion_data[i].major == fw_major) &&
+                  (negop->icversion_data[i].minor == fw_minor)) {
+                       icframe_major = negop->icversion_data[i].major;
+                       icframe_minor = negop->icversion_data[i].minor;
+                       found_match = true;
+               }
        }
 
+       if (!found_match)
+               goto fw_error;
+
+       found_match = false;
+
        for (i = negop->icframe_vercnt;
                 (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
-               if (negop->icversion_data[i].major <= max_srv_version)
-                       icmsg_vercnt = negop->icversion_data[i].major;
+               if ((negop->icversion_data[i].major == srv_major) &&
+                  (negop->icversion_data[i].minor == srv_minor)) {
+                       icmsg_major = negop->icversion_data[i].major;
+                       icmsg_minor = negop->icversion_data[i].minor;
+                       found_match = true;
+               }
        }
 
        /*
-        * Respond with the maximum framework and service
+        * Respond with the framework and service
         * version numbers we can support.
         */
-       negop->icframe_vercnt = 1;
-       negop->icmsg_vercnt = 1;
-       negop->icversion_data[0].major = icframe_vercnt;
-       negop->icversion_data[0].minor = 0;
-       negop->icversion_data[1].major = icmsg_vercnt;
-       negop->icversion_data[1].minor = 0;
+
+fw_error:
+       if (!found_match) {
+               negop->icframe_vercnt = 0;
+               negop->icmsg_vercnt = 0;
+       } else {
+               negop->icframe_vercnt = 1;
+               negop->icmsg_vercnt = 1;
+       }
+
+       negop->icversion_data[0].major = icframe_major;
+       negop->icversion_data[0].minor = icframe_minor;
+       negop->icversion_data[1].major = icmsg_major;
+       negop->icversion_data[1].minor = icmsg_minor;
+       return found_match;
 }
 
 EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
@@ -261,6 +292,13 @@ static void vmbus_process_offer(struct work_struct *work)
                return;
        }
 
+       /*
+        * This state is used to indicate a successful open
+        * so that when we do close the channel normally, we
+        * can cleanup properly
+        */
+       newchannel->state = CHANNEL_OPEN_STATE;
+
        /*
         * Start the process of binding this offer to the driver
         * We need to set the DeviceObject field before calling
@@ -287,13 +325,6 @@ static void vmbus_process_offer(struct work_struct *work)
                kfree(newchannel->device_obj);
 
                free_channel(newchannel);
-       } else {
-               /*
-                * This state is used to indicate a successful open
-                * so that when we do close the channel normally, we
-                * can cleanup properly
-                */
-               newchannel->state = CHANNEL_OPEN_STATE;
        }
 }