Commit 3f4071cb authored by Cristian Marussi's avatar Cristian Marussi Committed by Sudeep Holla

firmware: arm_scmi: Cleanup the core driver removal callback

Platform drivers .remove callbacks are not supposed to fail and report
errors. Such errors are indeed ignored by the core platform drivers
and the driver unbind process is anyway completed.

The SCMI core platform driver as it is now, instead, bails out reporting
an error in case of an explicit unbind request.

Fix the removal path by adding proper device links between the core SCMI
device and the SCMI protocol devices so that a full SCMI stack unbind is
triggered when the core driver is removed. The remove process does not
bail out anymore on the anomalous conditions triggered by an explicit
unbind but the user is still warned.
Reported-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: default avatarCristian Marussi <cristian.marussi@arm.com>
Link: https://lore.kernel.org/r/20221028140833.280091-1-cristian.marussi@arm.comSigned-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
parent 9abf2313
...@@ -216,9 +216,20 @@ void scmi_device_destroy(struct scmi_device *scmi_dev) ...@@ -216,9 +216,20 @@ void scmi_device_destroy(struct scmi_device *scmi_dev)
device_unregister(&scmi_dev->dev); device_unregister(&scmi_dev->dev);
} }
void scmi_device_link_add(struct device *consumer, struct device *supplier)
{
struct device_link *link;
link = device_link_add(consumer, supplier, DL_FLAG_AUTOREMOVE_CONSUMER);
WARN_ON(!link);
}
void scmi_set_handle(struct scmi_device *scmi_dev) void scmi_set_handle(struct scmi_device *scmi_dev)
{ {
scmi_dev->handle = scmi_handle_get(&scmi_dev->dev); scmi_dev->handle = scmi_handle_get(&scmi_dev->dev);
if (scmi_dev->handle)
scmi_device_link_add(&scmi_dev->dev, scmi_dev->handle->dev);
} }
int scmi_protocol_register(const struct scmi_protocol *proto) int scmi_protocol_register(const struct scmi_protocol *proto)
......
...@@ -97,6 +97,7 @@ static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr) ...@@ -97,6 +97,7 @@ static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr)
struct scmi_revision_info * struct scmi_revision_info *
scmi_revision_area_get(const struct scmi_protocol_handle *ph); scmi_revision_area_get(const struct scmi_protocol_handle *ph);
int scmi_handle_put(const struct scmi_handle *handle); int scmi_handle_put(const struct scmi_handle *handle);
void scmi_device_link_add(struct device *consumer, struct device *supplier);
struct scmi_handle *scmi_handle_get(struct device *dev); struct scmi_handle *scmi_handle_get(struct device *dev);
void scmi_set_handle(struct scmi_device *scmi_dev); void scmi_set_handle(struct scmi_device *scmi_dev);
void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph, void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
......
...@@ -2273,10 +2273,16 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table) ...@@ -2273,10 +2273,16 @@ int scmi_protocol_device_request(const struct scmi_device_id *id_table)
sdev = scmi_get_protocol_device(child, info, sdev = scmi_get_protocol_device(child, info,
id_table->protocol_id, id_table->protocol_id,
id_table->name); id_table->name);
/* Set handle if not already set: device existed */ if (sdev) {
if (sdev && !sdev->handle) /* Set handle if not already set: device existed */
sdev->handle = if (!sdev->handle)
scmi_handle_get_from_info_unlocked(info); 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 { } else {
dev_err(info->dev, dev_err(info->dev,
"Failed. SCMI protocol %d not active.\n", "Failed. SCMI protocol %d not active.\n",
...@@ -2475,20 +2481,17 @@ void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id) ...@@ -2475,20 +2481,17 @@ void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id)
static int scmi_remove(struct platform_device *pdev) static int scmi_remove(struct platform_device *pdev)
{ {
int ret = 0, id; int ret, id;
struct scmi_info *info = platform_get_drvdata(pdev); struct scmi_info *info = platform_get_drvdata(pdev);
struct device_node *child; struct device_node *child;
mutex_lock(&scmi_list_mutex); mutex_lock(&scmi_list_mutex);
if (info->users) if (info->users)
ret = -EBUSY; dev_warn(&pdev->dev,
else "Still active SCMI users will be forcibly unbound.\n");
list_del(&info->node); list_del(&info->node);
mutex_unlock(&scmi_list_mutex); mutex_unlock(&scmi_list_mutex);
if (ret)
return ret;
scmi_notification_exit(&info->handle); scmi_notification_exit(&info->handle);
mutex_lock(&info->protocols_mtx); mutex_lock(&info->protocols_mtx);
...@@ -2500,7 +2503,11 @@ static int scmi_remove(struct platform_device *pdev) ...@@ -2500,7 +2503,11 @@ static int scmi_remove(struct platform_device *pdev)
idr_destroy(&info->active_protocols); idr_destroy(&info->active_protocols);
/* Safe to free channels since no more users */ /* 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, static ssize_t protocol_version_show(struct device *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment