[PATCH] media: ipu7: fix boot config memory leak and replace polling loops

shayderrr posted 1 patch 1 week ago
drivers/staging/media/ipu7/ipu7-boot.c | 88 +++++++++++---------------
1 file changed, 36 insertions(+), 52 deletions(-)
[PATCH] media: ipu7: fix boot config memory leak and replace polling loops
Posted by shayderrr 1 week ago
From: Pranav Bajjuri <darknessshayder@gmail.com>

Free boot_config DMA allocation if queue memory alloc fails in
ipu7_boot_init_boot_config(). Replace hand-rolled timeout loops in
ipu7_boot_start_fw() and ipu7_boot_stop_fw() with read_poll_timeout().
Fix variable declaration order in cell reset, start, and stop to follow
reverse Christmas tree convention.

Signed-off-by: Pranav Bajjuri <darknessshayder@gmail.com>
---
 drivers/staging/media/ipu7/ipu7-boot.c | 88 +++++++++++---------------
 1 file changed, 36 insertions(+), 52 deletions(-)

diff --git a/drivers/staging/media/ipu7/ipu7-boot.c b/drivers/staging/media/ipu7/ipu7-boot.c
index d7901ff78b38..f081c39604a7 100644
--- a/drivers/staging/media/ipu7/ipu7-boot.c
+++ b/drivers/staging/media/ipu7/ipu7-boot.c
@@ -22,8 +22,8 @@
 #include "ipu7-platform-regs.h"
 #include "ipu7-syscom.h"
 
-#define IPU_FW_START_STOP_TIMEOUT		2000
-#define IPU_BOOT_CELL_RESET_TIMEOUT		(2 * USEC_PER_SEC)
+#define IPU_FW_START_STOP_TIMEOUT	2000
+#define IPU_BOOT_CELL_RESET_TIMEOUT	(2 * USEC_PER_SEC)
 #define BOOT_STATE_IS_CRITICAL(s)	IA_GOFO_FW_BOOT_STATE_IS_CRITICAL(s)
 #define BOOT_STATE_IS_READY(s)		((s) == IA_GOFO_FW_BOOT_STATE_READY)
 #define BOOT_STATE_IS_INACTIVE(s)	((s) == IA_GOFO_FW_BOOT_STATE_INACTIVE)
@@ -39,17 +39,17 @@ struct ipu7_boot_context {
 static const struct ipu7_boot_context contexts[IPU_SUBSYS_NUM] = {
 	{
 		/* ISYS */
-		.dmem_address = IPU_ISYS_DMEM_OFFSET,
-		.status_ctrl_reg = BUTTRESS_REG_DRV_IS_UCX_CONTROL_STATUS,
-		.fw_start_address_reg = BUTTRESS_REG_DRV_IS_UCX_START_ADDR,
-		.fw_code_base_reg = IS_UC_CTRL_BASE
+		.dmem_address		= IPU_ISYS_DMEM_OFFSET,
+		.status_ctrl_reg	= BUTTRESS_REG_DRV_IS_UCX_CONTROL_STATUS,
+		.fw_start_address_reg	= BUTTRESS_REG_DRV_IS_UCX_START_ADDR,
+		.fw_code_base_reg	= IS_UC_CTRL_BASE
 	},
 	{
 		/* PSYS */
-		.dmem_address = IPU_PSYS_DMEM_OFFSET,
-		.status_ctrl_reg = BUTTRESS_REG_DRV_PS_UCX_CONTROL_STATUS,
-		.fw_start_address_reg = BUTTRESS_REG_DRV_PS_UCX_START_ADDR,
-		.fw_code_base_reg = PS_UC_CTRL_BASE
+		.dmem_address		= IPU_PSYS_DMEM_OFFSET,
+		.status_ctrl_reg	= BUTTRESS_REG_DRV_PS_UCX_CONTROL_STATUS,
+		.fw_start_address_reg	= BUTTRESS_REG_DRV_PS_UCX_START_ADDR,
+		.fw_code_base_reg	= PS_UC_CTRL_BASE
 	}
 };
 
@@ -85,9 +85,9 @@ static int ipu7_boot_cell_reset(const struct ipu7_bus_device *adev)
 {
 	const struct ipu7_boot_context *ctx = &contexts[adev->subsys];
 	const struct device *dev = &adev->auxdev.dev;
+	void __iomem *base = adev->isp->base;
 	u32 ucx_ctrl_status = ctx->status_ctrl_reg;
 	u32 timeout = IPU_BOOT_CELL_RESET_TIMEOUT;
-	void __iomem *base = adev->isp->base;
 	u32 val, val2;
 	int ret;
 
@@ -134,8 +134,8 @@ static int ipu7_boot_cell_reset(const struct ipu7_bus_device *adev)
 static void ipu7_boot_cell_start(const struct ipu7_bus_device *adev)
 {
 	const struct ipu7_boot_context *ctx = &contexts[adev->subsys];
-	void __iomem *base = adev->isp->base;
 	const struct device *dev = &adev->auxdev.dev;
+	void __iomem *base = adev->isp->base;
 	u32 val;
 
 	dev_dbg(dev, "starting cell...\n");
@@ -152,8 +152,8 @@ static void ipu7_boot_cell_start(const struct ipu7_bus_device *adev)
 static void ipu7_boot_cell_stop(const struct ipu7_bus_device *adev)
 {
 	const struct ipu7_boot_context *ctx = &contexts[adev->subsys];
-	void __iomem *base = adev->isp->base;
 	const struct device *dev = &adev->auxdev.dev;
+	void __iomem *base = adev->isp->base;
 	u32 val;
 
 	dev_dbg(dev, "stopping cell...\n");
@@ -187,16 +187,14 @@ static int ipu7_boot_cell_init(const struct ipu7_bus_device *adev)
 }
 
 static void init_boot_config(struct ia_gofo_boot_config *boot_config,
-			     u32 length, u8 major)
+			     u32 config_size, u8 major)
 {
-	/* syscom version, new syscom2 version */
-	boot_config->length = length;
+	boot_config->length = config_size;
 	boot_config->config_version.major = 1U;
 	boot_config->config_version.minor = 0U;
 	boot_config->config_version.subminor = 0U;
 	boot_config->config_version.patch = 0U;
 
-	/* msg version for task interface */
 	boot_config->client_version_support.num_versions = 1U;
 	boot_config->client_version_support.versions[0].major = major;
 	boot_config->client_version_support.versions[0].minor = 0U;
@@ -221,7 +219,7 @@ int ipu7_boot_init_boot_config(struct ipu7_bus_device *adev,
 
 	dev_dbg(dev, "boot config queues_nr: %d freq: %u sys_conf: 0x%pad\n",
 		num_queues, uc_freq, &subsys_config);
-	/* Allocate boot config. */
+
 	adev->boot_config_size =
 		sizeof(*cfgs) * num_queues + sizeof(*boot_config);
 	adev->boot_config = ipu7_dma_alloc(adev, adev->boot_config_size,
@@ -257,12 +255,15 @@ int ipu7_boot_init_boot_config(struct ipu7_bus_device *adev,
 		qconfigs[i].queue_size = queue_size;
 	}
 
-	/* Allocate queue memory */
 	syscom->queue_mem = ipu7_dma_alloc(adev, total_queue_size_aligned,
 					   &syscom->queue_mem_dma_addr,
 					   GFP_KERNEL, 0);
 	if (!syscom->queue_mem) {
 		dev_err(dev, "Failed to allocate queue memory.\n");
+		ipu7_dma_free(adev, adev->boot_config_size,
+			      adev->boot_config,
+			      adev->boot_config_dma_addr, 0);
+		adev->boot_config = NULL;
 		return -ENOMEM;
 	}
 	syscom->queue_mem_size = total_queue_size_aligned;
@@ -312,7 +313,6 @@ EXPORT_SYMBOL_NS_GPL(ipu7_boot_release_boot_config, "INTEL_IPU7");
 int ipu7_boot_start_fw(const struct ipu7_bus_device *adev)
 {
 	const struct device *dev = &adev->auxdev.dev;
-	u32 timeout = IPU_FW_START_STOP_TIMEOUT;
 	void __iomem *base = adev->isp->base;
 	u32 boot_state, last_boot_state;
 	u32 indices_addr, msg_ver, id;
@@ -323,37 +323,26 @@ int ipu7_boot_start_fw(const struct ipu7_bus_device *adev)
 		return ret;
 
 	dev_dbg(dev, "start booting fw...\n");
-	/* store "uninit" state to syscom/boot state reg */
 	write_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID,
 			    IA_GOFO_FW_BOOT_STATE_UNINIT);
-	/*
-	 * Set registers to zero
-	 * (not strictly required, but recommended for diagnostics)
-	 */
 	write_fw_boot_param(adev,
 			    IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID, 0);
 	write_fw_boot_param(adev, IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID, 0);
-	/* store firmware configuration address */
 	write_fw_boot_param(adev, IA_GOFO_FW_BOOT_CONFIG_ID,
 			    adev->boot_config_dma_addr);
 
-	/* Kick uC, then wait for boot complete */
 	ipu7_boot_cell_start(adev);
 
 	last_boot_state = IA_GOFO_FW_BOOT_STATE_UNINIT;
-	while (timeout--) {
-		boot_state = read_fw_boot_param(adev,
-						IA_GOFO_FW_BOOT_STATE_ID);
-		if (boot_state != last_boot_state) {
-			dev_dbg(dev, "boot state changed from 0x%x to 0x%x\n",
-				last_boot_state, boot_state);
-			last_boot_state = boot_state;
-		}
-		if (BOOT_STATE_IS_CRITICAL(boot_state) ||
-		    BOOT_STATE_IS_READY(boot_state))
-			break;
-		usleep_range(1000, 1200);
-	}
+	ret = read_poll_timeout(read_fw_boot_param, boot_state,
+				BOOT_STATE_IS_CRITICAL(boot_state) ||
+				BOOT_STATE_IS_READY(boot_state),
+				1000, IPU_FW_START_STOP_TIMEOUT * 1000ULL,
+				false, adev, IA_GOFO_FW_BOOT_STATE_ID);
+
+	if (boot_state != last_boot_state)
+		dev_dbg(dev, "boot state changed from 0x%x to 0x%x\n",
+			last_boot_state, boot_state);
 
 	if (BOOT_STATE_IS_CRITICAL(boot_state)) {
 		ipu7_dump_fw_error_log(adev);
@@ -365,13 +354,11 @@ int ipu7_boot_start_fw(const struct ipu7_bus_device *adev)
 	}
 	dev_dbg(dev, "fw boot done.\n");
 
-	/* Get FW syscom queue indices addr */
 	id = IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID;
 	indices_addr = read_fw_boot_param(adev, id);
 	adev->syscom->queue_indices = base + indices_addr;
 	dev_dbg(dev, "fw queue indices offset is 0x%x\n", indices_addr);
 
-	/* Get message version. */
 	msg_ver = read_fw_boot_param(adev,
 				     IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID);
 	dev_dbg(dev, "ipu message version is 0x%08x\n", msg_ver);
@@ -383,8 +370,8 @@ EXPORT_SYMBOL_NS_GPL(ipu7_boot_start_fw, "INTEL_IPU7");
 int ipu7_boot_stop_fw(const struct ipu7_bus_device *adev)
 {
 	const struct device *dev = &adev->auxdev.dev;
-	u32 timeout = IPU_FW_START_STOP_TIMEOUT;
 	u32 boot_state;
+	int ret;
 
 	boot_state = read_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID);
 	if (BOOT_STATE_IS_CRITICAL(boot_state) ||
@@ -394,18 +381,15 @@ int ipu7_boot_stop_fw(const struct ipu7_bus_device *adev)
 		return -EBUSY;
 	}
 
-	/* Issue shutdown to start shutdown process */
 	dev_dbg(dev, "stopping fw...\n");
 	write_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID,
 			    IA_GOFO_FW_BOOT_STATE_SHUTDOWN_CMD);
-	while (timeout--) {
-		boot_state = read_fw_boot_param(adev,
-						IA_GOFO_FW_BOOT_STATE_ID);
-		if (BOOT_STATE_IS_CRITICAL(boot_state) ||
-		    BOOT_STATE_IS_INACTIVE(boot_state))
-			break;
-		usleep_range(1000, 1200);
-	}
+
+	ret = read_poll_timeout(read_fw_boot_param, boot_state,
+				BOOT_STATE_IS_CRITICAL(boot_state) ||
+				BOOT_STATE_IS_INACTIVE(boot_state),
+				1000, IPU_FW_START_STOP_TIMEOUT * 1000ULL,
+				false, adev, IA_GOFO_FW_BOOT_STATE_ID);
 
 	if (BOOT_STATE_IS_CRITICAL(boot_state)) {
 		ipu7_dump_fw_error_log(adev);
-- 
2.50.1 (Apple Git-155)
Re: [PATCH] media: ipu7: fix boot config memory leak and replace polling loops
Posted by kernel test robot 1 week ago
Hi shayderrr,

kernel test robot noticed the following build warnings:

[auto build test WARNING on staging/staging-testing]
[also build test WARNING on staging/staging-next staging/staging-linus sailus-media-tree/master linuxtv-media-pending/master linus/master v7.1-rc4 next-20260508]
[cannot apply to sailus-media-tree/streams]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/shayderrr/media-ipu7-fix-boot-config-memory-leak-and-replace-polling-loops/20260517-223602
base:   staging/staging-testing
patch link:    https://lore.kernel.org/r/20260517143456.81109-1-darknessshayder%40gmail.com
patch subject: [PATCH] media: ipu7: fix boot config memory leak and replace polling loops
config: i386-allyesconfig (https://download.01.org/0day-ci/archive/20260518/202605180756.c4CIIUw4-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260518/202605180756.c4CIIUw4-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605180756.c4CIIUw4-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/staging/media/ipu7/ipu7-boot.c: In function 'ipu7_boot_stop_fw':
>> drivers/staging/media/ipu7/ipu7-boot.c:374:13: warning: variable 'ret' set but not used [-Wunused-but-set-variable]
     374 |         int ret;
         |             ^~~


vim +/ret +374 drivers/staging/media/ipu7/ipu7-boot.c

   369	
   370	int ipu7_boot_stop_fw(const struct ipu7_bus_device *adev)
   371	{
   372		const struct device *dev = &adev->auxdev.dev;
   373		u32 boot_state;
 > 374		int ret;
   375	
   376		boot_state = read_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID);
   377		if (BOOT_STATE_IS_CRITICAL(boot_state) ||
   378		    !BOOT_STATE_IS_READY(boot_state)) {
   379			dev_err(dev, "fw not ready for shutdown, state 0x%x\n",
   380				boot_state);
   381			return -EBUSY;
   382		}
   383	
   384		dev_dbg(dev, "stopping fw...\n");
   385		write_fw_boot_param(adev, IA_GOFO_FW_BOOT_STATE_ID,
   386				    IA_GOFO_FW_BOOT_STATE_SHUTDOWN_CMD);
   387	
   388		ret = read_poll_timeout(read_fw_boot_param, boot_state,
   389					BOOT_STATE_IS_CRITICAL(boot_state) ||
   390					BOOT_STATE_IS_INACTIVE(boot_state),
   391					1000, IPU_FW_START_STOP_TIMEOUT * 1000ULL,
   392					false, adev, IA_GOFO_FW_BOOT_STATE_ID);
   393	
   394		if (BOOT_STATE_IS_CRITICAL(boot_state)) {
   395			ipu7_dump_fw_error_log(adev);
   396			dev_err(dev, "critical boot state error 0x%x\n", boot_state);
   397			return -EINVAL;
   398		} else if (!BOOT_STATE_IS_INACTIVE(boot_state)) {
   399			dev_err(dev, "stop fw timeout. state: 0x%x\n", boot_state);
   400			return -ETIMEDOUT;
   401		}
   402	
   403		ipu7_boot_cell_stop(adev);
   404		dev_dbg(dev, "stop fw done.\n");
   405	
   406		return 0;
   407	}
   408	EXPORT_SYMBOL_NS_GPL(ipu7_boot_stop_fw, "INTEL_IPU7");
   409	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki