Merge branch 'pm-opp'
[firefly-linux-kernel-4.4.55.git] / drivers / misc / mei / hbm.c
index 8a73fa06f3c4536b36b19b0dea2bc6ea2ad3e824..8eec887c8f701ce732a6278a49b1fbe298ca0635 100644 (file)
@@ -52,6 +52,7 @@ static const char *mei_cl_conn_status_str(enum mei_cl_connect_status status)
        MEI_CL_CS(ALREADY_STARTED);
        MEI_CL_CS(OUT_OF_RESOURCES);
        MEI_CL_CS(MESSAGE_SMALL);
+       MEI_CL_CS(NOT_ALLOWED);
        default: return "unknown";
        }
 #undef MEI_CL_CCS
@@ -89,6 +90,7 @@ static int mei_cl_conn_status_to_errno(enum mei_cl_connect_status status)
        case MEI_CL_CONN_ALREADY_STARTED:  return -EBUSY;
        case MEI_CL_CONN_OUT_OF_RESOURCES: return -EBUSY;
        case MEI_CL_CONN_MESSAGE_SMALL:    return -EINVAL;
+       case MEI_CL_CONN_NOT_ALLOWED:      return -EBUSY;
        default:                           return -EINVAL;
        }
 }
@@ -446,10 +448,7 @@ static inline enum mei_cb_file_ops notify_res_to_fop(struct mei_hbm_cl_cmd *cmd)
        struct hbm_notification_response *rs =
                (struct hbm_notification_response *)cmd;
 
-       if (rs->start == MEI_HBM_NOTIFICATION_START)
-               return MEI_FOP_NOTIFY_START;
-       else
-               return MEI_FOP_NOTIFY_STOP;
+       return mei_cl_notify_req2fop(rs->start);
 }
 
 /**
@@ -517,8 +516,8 @@ static void mei_hbm_cl_notify(struct mei_device *dev,
        struct mei_cl *cl;
 
        cl = mei_hbm_cl_find_by_cmd(dev, cmd);
-       if (cl && cl->notify_en)
-               cl->notify_ev = true;
+       if (cl)
+               mei_cl_notify(cl);
 }
 
 /**
@@ -880,6 +879,79 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
        return 0;
 }
 
+/**
+ * mei_hbm_pg_enter_res - PG enter response received
+ *
+ * @dev: the device structure.
+ *
+ * Return: 0 on success, -EPROTO on state mismatch
+ */
+static int mei_hbm_pg_enter_res(struct mei_device *dev)
+{
+       if (mei_pg_state(dev) != MEI_PG_OFF ||
+           dev->pg_event != MEI_PG_EVENT_WAIT) {
+               dev_err(dev->dev, "hbm: pg entry response: state mismatch [%s, %d]\n",
+                       mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);
+               return -EPROTO;
+       }
+
+       dev->pg_event = MEI_PG_EVENT_RECEIVED;
+       wake_up(&dev->wait_pg);
+
+       return 0;
+}
+
+/**
+ * mei_hbm_pg_resume - process with PG resume
+ *
+ * @dev: the device structure.
+ */
+void mei_hbm_pg_resume(struct mei_device *dev)
+{
+       pm_request_resume(dev->dev);
+}
+EXPORT_SYMBOL_GPL(mei_hbm_pg_resume);
+
+/**
+ * mei_hbm_pg_exit_res - PG exit response received
+ *
+ * @dev: the device structure.
+ *
+ * Return: 0 on success, -EPROTO on state mismatch
+ */
+static int mei_hbm_pg_exit_res(struct mei_device *dev)
+{
+       if (mei_pg_state(dev) != MEI_PG_ON ||
+           (dev->pg_event != MEI_PG_EVENT_WAIT &&
+            dev->pg_event != MEI_PG_EVENT_IDLE)) {
+               dev_err(dev->dev, "hbm: pg exit response: state mismatch [%s, %d]\n",
+                       mei_pg_state_str(mei_pg_state(dev)), dev->pg_event);
+               return -EPROTO;
+       }
+
+       switch (dev->pg_event) {
+       case MEI_PG_EVENT_WAIT:
+               dev->pg_event = MEI_PG_EVENT_RECEIVED;
+               wake_up(&dev->wait_pg);
+               break;
+       case MEI_PG_EVENT_IDLE:
+               /*
+               * If the driver is not waiting on this then
+               * this is HW initiated exit from PG.
+               * Start runtime pm resume sequence to exit from PG.
+               */
+               dev->pg_event = MEI_PG_EVENT_RECEIVED;
+               mei_hbm_pg_resume(dev);
+               break;
+       default:
+               WARN(1, "hbm: pg exit response: unexpected pg event = %d\n",
+                    dev->pg_event);
+               return -EPROTO;
+       }
+
+       return 0;
+}
+
 /**
  * mei_hbm_config_features - check what hbm features and commands
  *        are supported by the fw
@@ -903,6 +975,10 @@ static void mei_hbm_config_features(struct mei_device *dev)
        /* disconnect on connect timeout instead of link reset */
        if (dev->version.major_version >= HBM_MAJOR_VERSION_DOT)
                dev->hbm_f_dot_supported = 1;
+
+       /* Notification Event Support */
+       if (dev->version.major_version >= HBM_MAJOR_VERSION_EV)
+               dev->hbm_f_ev_supported = 1;
 }
 
 /**
@@ -1024,24 +1100,17 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
                break;
 
        case MEI_PG_ISOLATION_ENTRY_RES_CMD:
-               dev_dbg(dev->dev, "power gate isolation entry response received\n");
-               dev->pg_event = MEI_PG_EVENT_RECEIVED;
-               if (waitqueue_active(&dev->wait_pg))
-                       wake_up(&dev->wait_pg);
+               dev_dbg(dev->dev, "hbm: power gate isolation entry response received\n");
+               ret = mei_hbm_pg_enter_res(dev);
+               if (ret)
+                       return ret;
                break;
 
        case MEI_PG_ISOLATION_EXIT_REQ_CMD:
-               dev_dbg(dev->dev, "power gate isolation exit request received\n");
-               dev->pg_event = MEI_PG_EVENT_RECEIVED;
-               if (waitqueue_active(&dev->wait_pg))
-                       wake_up(&dev->wait_pg);
-               else
-                       /*
-                       * If the driver is not waiting on this then
-                       * this is HW initiated exit from PG.
-                       * Start runtime pm resume sequence to exit from PG.
-                       */
-                       pm_request_resume(dev->dev);
+               dev_dbg(dev->dev, "hbm: power gate isolation exit request received\n");
+               ret = mei_hbm_pg_exit_res(dev);
+               if (ret)
+                       return ret;
                break;
 
        case HOST_CLIENT_PROPERTIES_RES_CMD: