Arm SCMI fixes for v6.15

Couple of fixes addressing issues with timeout in the polling path
 and device reference count imbalance detected by kmemleak.
 
 1. The change fixes a timeout issue in the polling path of SCMI transactions
    where false positives could occur if the polling thread was pre-empted,
    causing it to appear as though a timeout occurred when it hadn't. The fix
    ensures that the polling result is verified before reporting a timeout,
    accounting for potential pre-emption or out-of-order replies.
 
 2. It also corrects a device reference count imbalance caused by
    device_find_child() during device destruction, which prevented proper
    cleanup and triggered memory leaks detected by KMemleak.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEunHlEgbzHrJD3ZPhAEG6vDF+4pgFAmf3xWIACgkQAEG6vDF+
 4pjBlQ/9GMfp/FSSVLoUOqUypjkV0U6if1hLHWmqS0EaSi+2eA1oeFms91/KJm5x
 s3KHH/YOcdwn7Xej+CJNugTdvp44nUAkkgq0FNoIkSliHznpWJutIH9C0uDe1pLI
 wdIHrwXbsvtW4jK0uSL8ZOZWVDpMV3fFjJX+HZqlP7mQTUIo0lh7oIn02X0vrmYE
 tNZGYBH2SOv0SPqcI1rcRj5VzroRk6eOK81MJMqWRzkfjDRkTRRaigPojZKHlHaL
 jHGYBualK7Qz8rExVtrJ1EaraBQsxXBixYQct0pck7bDQrUlUwZjLr75Jc1aCHnI
 fXmkS8nvuLnuXOJ/BWxdqS5cLlP8vycBYfOcOd0Say6VVrhBp38lpbunZWKsq9rX
 LgnBWqEUouOvYM+p923xsISj1r0SZu0y+jfummDGandHFzH9zEi+mwEnylQuFROz
 1MPtZ6qSstxRXBdqaszoNlTiXIb26LPA5ywomLDln/SLgsYgTIQErqTH7w8yauQq
 zPW0I1NQL/+goIa9q12Qc4lu2hQotYpoPBJK2oTgTf7fKlCgjukrFX7Q+vIstNfd
 IEOSskgDeCJ8Rc81ZBPb7fhxKY4RzIsgtoplFRNjAIUOE4dZvYD47k7e2+jMVemT
 YUWSP3ILSSBBGjJNv6TRIaMj11e2SsR4wc9eF4giHxRTrrTEXTA=
 =JEKv
 -----END PGP SIGNATURE-----

Merge tag 'scmi-fixes-6.15' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes

Arm SCMI fixes for v6.15

Couple of fixes addressing issues with timeout in the polling path
and device reference count imbalance detected by kmemleak.

1. The change fixes a timeout issue in the polling path of SCMI transactions
   where false positives could occur if the polling thread was pre-empted,
   causing it to appear as though a timeout occurred when it hadn't. The fix
   ensures that the polling result is verified before reporting a timeout,
   accounting for potential pre-emption or out-of-order replies.

2. It also corrects a device reference count imbalance caused by
   device_find_child() during device destruction, which prevented proper
   cleanup and triggered memory leaks detected by KMemleak.

* tag 'scmi-fixes-6.15' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Fix timeout checks on polling path
  firmware: arm_scmi: Balance device refcount when destroying devices
This commit is contained in:
Arnd Bergmann 2025-04-29 18:14:03 +02:00
commit 94ddc14095
2 changed files with 11 additions and 5 deletions

View File

@ -255,6 +255,9 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent,
if (!dev)
return NULL;
/* Drop the refcnt bumped implicitly by device_find_child */
put_device(dev);
return to_scmi_dev(dev);
}

View File

@ -1248,7 +1248,8 @@ static void xfer_put(const struct scmi_protocol_handle *ph,
}
static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
struct scmi_xfer *xfer, ktime_t stop)
struct scmi_xfer *xfer, ktime_t stop,
bool *ooo)
{
struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
@ -1257,7 +1258,7 @@ static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo,
* in case of out-of-order receptions of delayed responses
*/
return info->desc->ops->poll_done(cinfo, xfer) ||
try_wait_for_completion(&xfer->done) ||
(*ooo = try_wait_for_completion(&xfer->done)) ||
ktime_after(ktime_get(), stop);
}
@ -1274,15 +1275,17 @@ static int scmi_wait_for_reply(struct device *dev, const struct scmi_desc *desc,
* itself to support synchronous commands replies.
*/
if (!desc->sync_cmds_completed_on_ret) {
bool ooo = false;
/*
* Poll on xfer using transport provided .poll_done();
* assumes no completion interrupt was available.
*/
ktime_t stop = ktime_add_ms(ktime_get(), timeout_ms);
spin_until_cond(scmi_xfer_done_no_timeout(cinfo,
xfer, stop));
if (ktime_after(ktime_get(), stop)) {
spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer,
stop, &ooo));
if (!ooo && !info->desc->ops->poll_done(cinfo, xfer)) {
dev_err(dev,
"timed out in resp(caller: %pS) - polling\n",
(void *)_RET_IP_);