firmware: arm_scmi: Fix chan_free cleanup on SMC
[ Upstream commitd1ff11d7ad
] 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:dd820ee21d
("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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
6289d5486d
commit
5b53b2b44f
|
@ -23,6 +23,7 @@
|
|||
/**
|
||||
* 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.
|
||||
|
@ -33,6 +34,7 @@
|
|||
*/
|
||||
|
||||
struct scmi_smc {
|
||||
int irq;
|
||||
struct scmi_chan_info *cinfo;
|
||||
struct scmi_shared_mem __iomem *shmem;
|
||||
/* Protect access to shmem area */
|
||||
|
@ -106,7 +108,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;
|
||||
|
@ -142,11 +144,10 @@ 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;
|
||||
|
@ -168,6 +169,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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue