Skip to content
Snippets Groups Projects
Commit 18126b26 authored by Cristian Marussi's avatar Cristian Marussi Committed by Lee Jones
Browse files

UPSTREAM: firmware: arm_scmi: Fix chan_free cleanup on SMC


SCMI transport based on SMC can optionally use an additional IRQ to
signal message completion. The associated interrupt handler is currently
allocated using devres but on shutdown the core SCMI stack will call
.chan_free() well before any managed cleanup is invoked by devres.
As a consequence, the arrival of a late reply to an in-flight pending
transaction could still trigger the interrupt handler well after the
SCMI core has cleaned up the channels, with unpleasant results.

Inhibit further message processing on the IRQ path by explicitly freeing
the IRQ inside .chan_free() callback itself.

Bug: 254441685
Fixes: dd820ee2 ("firmware: arm_scmi: Augment SMC/HVC to allow optional interrupt")
Reported-by: default avatarBjorn Andersson <andersson@kernel.org>
Signed-off-by: default avatarCristian Marussi <cristian.marussi@arm.com>
Link: https://lore.kernel.org/r/20230719173533.2739319-1-cristian.marussi@arm.com


Signed-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
(cherry picked from commit d1ff11d7)
Signed-off-by: default avatarLee Jones <joneslee@google.com>
Change-Id: I9996056d3dddd9b208de7e5afb5aa3d345325e01
parent 2d2a6139
No related merge requests found
......@@ -21,20 +21,20 @@
/**
* struct scmi_smc - Structure representing a SCMI smc transport
*
* @irq: An optional IRQ for completion
* @cinfo: SCMI channel info
* @shmem: Transmit/Receive shared memory area
* @shmem_lock: Lock to protect access to Tx/Rx shared memory area
* @func_id: smc/hvc call function id
* @irq: Optional; employed when platforms indicates msg completion by intr.
* @tx_complete: Optional, employed only when irq is valid.
*/
struct scmi_smc {
int irq;
struct scmi_chan_info *cinfo;
struct scmi_shared_mem __iomem *shmem;
struct mutex shmem_lock;
u32 func_id;
int irq;
struct completion tx_complete;
};
......@@ -66,7 +66,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
struct resource res;
struct device_node *np;
u32 func_id;
int ret, irq;
int ret;
if (!tx)
return -ENODEV;
......@@ -99,17 +99,15 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
* completion of a message is signaled by an interrupt rather than by
* the return of the SMC call.
*/
irq = of_irq_get_byname(cdev->of_node, "a2p");
if (irq > 0) {
ret = devm_request_irq(dev, irq, smc_msg_done_isr,
IRQF_NO_SUSPEND,
dev_name(dev), scmi_info);
scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");
if (scmi_info->irq > 0) {
ret = request_irq(scmi_info->irq, smc_msg_done_isr,
IRQF_NO_SUSPEND, dev_name(dev), scmi_info);
if (ret) {
dev_err(dev, "failed to setup SCMI smc irq\n");
return ret;
}
init_completion(&scmi_info->tx_complete);
scmi_info->irq = irq;
}
scmi_info->func_id = func_id;
......@@ -125,6 +123,10 @@ static int smc_chan_free(int id, void *p, void *data)
struct scmi_chan_info *cinfo = p;
struct scmi_smc *scmi_info = cinfo->transport_info;
/* Ignore any possible further reception on the IRQ path */
if (scmi_info->irq > 0)
free_irq(scmi_info->irq, scmi_info);
cinfo->transport_info = NULL;
scmi_info->cinfo = NULL;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment