firmware: arm_scmi: Clear stale xfer->hdr.status
[platform/kernel/linux-rpi.git] / drivers / firmware / arm_scmi / driver.c
index b406b3f..1184249 100644 (file)
@@ -652,7 +652,8 @@ static void scmi_handle_response(struct scmi_chan_info *cinfo,
 
        xfer = scmi_xfer_command_acquire(cinfo, msg_hdr);
        if (IS_ERR(xfer)) {
-               scmi_clear_channel(info, cinfo);
+               if (MSG_XTRACT_TYPE(msg_hdr) == MSG_TYPE_DELAYED_RESP)
+                       scmi_clear_channel(info, cinfo);
                return;
        }
 
@@ -782,6 +783,8 @@ static int do_xfer(const struct scmi_protocol_handle *ph,
                              xfer->hdr.protocol_id, xfer->hdr.seq,
                              xfer->hdr.poll_completion);
 
+       /* Clear any stale status */
+       xfer->hdr.status = SCMI_SUCCESS;
        xfer->state = SCMI_XFER_SENT_OK;
        /*
         * Even though spinlocking is not needed here since no race is possible
@@ -1515,8 +1518,12 @@ scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
 {
        int ret = scmi_chan_setup(info, dev, prot_id, true);
 
-       if (!ret) /* Rx is optional, hence no error check */
-               scmi_chan_setup(info, dev, prot_id, false);
+       if (!ret) {
+               /* Rx is optional, report only memory errors */
+               ret = scmi_chan_setup(info, dev, prot_id, false);
+               if (ret && ret != -ENOMEM)
+                       ret = 0;
+       }
 
        return ret;
 }
@@ -1726,10 +1733,16 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table)
                        sdev = scmi_get_protocol_device(child, info,
                                                        id_table->protocol_id,
                                                        id_table->name);
-                       /* Set handle if not already set: device existed */
-                       if (sdev && !sdev->handle)
-                               sdev->handle =
-                                       scmi_handle_get_from_info_unlocked(info);
+                       if (sdev) {
+                               /* Set handle if not already set: device existed */
+                               if (!sdev->handle)
+                                       sdev->handle =
+                                               scmi_handle_get_from_info_unlocked(info);
+                               /* Relink consumer and suppliers */
+                               if (sdev->handle)
+                                       scmi_device_link_add(&sdev->dev,
+                                                            sdev->handle->dev);
+                       }
                } else {
                        dev_err(info->dev,
                                "Failed. SCMI protocol %d not active.\n",
@@ -1915,20 +1928,17 @@ void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id)
 
 static int scmi_remove(struct platform_device *pdev)
 {
-       int ret = 0, id;
+       int ret, id;
        struct scmi_info *info = platform_get_drvdata(pdev);
        struct device_node *child;
 
        mutex_lock(&scmi_list_mutex);
        if (info->users)
-               ret = -EBUSY;
-       else
-               list_del(&info->node);
+               dev_warn(&pdev->dev,
+                        "Still active SCMI users will be forcibly unbound.\n");
+       list_del(&info->node);
        mutex_unlock(&scmi_list_mutex);
 
-       if (ret)
-               return ret;
-
        scmi_notification_exit(&info->handle);
 
        mutex_lock(&info->protocols_mtx);
@@ -1940,7 +1950,11 @@ static int scmi_remove(struct platform_device *pdev)
        idr_destroy(&info->active_protocols);
 
        /* Safe to free channels since no more users */
-       return scmi_cleanup_txrx_channels(info);
+       ret = scmi_cleanup_txrx_channels(info);
+       if (ret)
+               dev_warn(&pdev->dev, "Failed to cleanup SCMI channels.\n");
+
+       return 0;
 }
 
 static ssize_t protocol_version_show(struct device *dev,
@@ -2008,6 +2022,7 @@ MODULE_DEVICE_TABLE(of, scmi_of_match);
 static struct platform_driver scmi_driver = {
        .driver = {
                   .name = "arm-scmi",
+                  .suppress_bind_attrs = true,
                   .of_match_table = scmi_of_match,
                   .dev_groups = versions_groups,
                   },
@@ -2112,7 +2127,7 @@ static void __exit scmi_driver_exit(void)
 }
 module_exit(scmi_driver_exit);
 
-MODULE_ALIAS("platform: arm-scmi");
+MODULE_ALIAS("platform:arm-scmi");
 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
 MODULE_DESCRIPTION("ARM SCMI protocol driver");
 MODULE_LICENSE("GPL v2");