Skip to content

Commit d1ff11d

Browse files
cris-masudeep-holla
authored andcommitted
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. Fixes: dd820ee ("firmware: arm_scmi: Augment SMC/HVC to allow optional interrupt") Reported-by: Bjorn Andersson <andersson@kernel.org> Signed-off-by: Cristian Marussi <cristian.marussi@arm.com> Link: https://lore.kernel.org/r/20230719173533.2739319-1-cristian.marussi@arm.com Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
1 parent da042eb commit d1ff11d

File tree

1 file changed

+11
-6
lines changed
  • drivers/firmware/arm_scmi

1 file changed

+11
-6
lines changed

drivers/firmware/arm_scmi/smc.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
/**
4141
* struct scmi_smc - Structure representing a SCMI smc transport
4242
*
43+
* @irq: An optional IRQ for completion
4344
* @cinfo: SCMI channel info
4445
* @shmem: Transmit/Receive shared memory area
4546
* @shmem_lock: Lock to protect access to Tx/Rx shared memory area.
@@ -52,6 +53,7 @@
5253
*/
5354

5455
struct scmi_smc {
56+
int irq;
5557
struct scmi_chan_info *cinfo;
5658
struct scmi_shared_mem __iomem *shmem;
5759
/* Protect access to shmem area */
@@ -127,7 +129,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
127129
struct resource res;
128130
struct device_node *np;
129131
u32 func_id;
130-
int ret, irq;
132+
int ret;
131133

132134
if (!tx)
133135
return -ENODEV;
@@ -169,11 +171,10 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
169171
* completion of a message is signaled by an interrupt rather than by
170172
* the return of the SMC call.
171173
*/
172-
irq = of_irq_get_byname(cdev->of_node, "a2p");
173-
if (irq > 0) {
174-
ret = devm_request_irq(dev, irq, smc_msg_done_isr,
175-
IRQF_NO_SUSPEND,
176-
dev_name(dev), scmi_info);
174+
scmi_info->irq = of_irq_get_byname(cdev->of_node, "a2p");
175+
if (scmi_info->irq > 0) {
176+
ret = request_irq(scmi_info->irq, smc_msg_done_isr,
177+
IRQF_NO_SUSPEND, dev_name(dev), scmi_info);
177178
if (ret) {
178179
dev_err(dev, "failed to setup SCMI smc irq\n");
179180
return ret;
@@ -195,6 +196,10 @@ static int smc_chan_free(int id, void *p, void *data)
195196
struct scmi_chan_info *cinfo = p;
196197
struct scmi_smc *scmi_info = cinfo->transport_info;
197198

199+
/* Ignore any possible further reception on the IRQ path */
200+
if (scmi_info->irq > 0)
201+
free_irq(scmi_info->irq, scmi_info);
202+
198203
cinfo->transport_info = NULL;
199204
scmi_info->cinfo = NULL;
200205

0 commit comments

Comments
 (0)