Commit 94ddc140 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'scmi-fixes-6.15' of...

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
parents 9c32cda4 c23c03bf
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
}

+8 −5
Original line number Diff line number Diff line
@@ -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_);