Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e531d359 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "i2c-msm-geni: KASAN: use-after-free in __list_add_valid+0x2c/0xc4"

parents 8be449ff ed404b2b
Loading
Loading
Loading
Loading
+51 −4
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
 */

#include <linux/clk.h>
@@ -136,10 +137,12 @@ struct geni_i2c_dev {
	bool disable_dma_mode;
	bool prev_cancel_pending; //Halt cancel till IOS in good state
	bool is_i2c_rtl_based; /* doing pending cancel only for rtl based SE's */
	atomic_t is_xfer_in_progress; /* Used to maintain xfer inprogress status */
};

static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE];
static int arr_idx;
static int geni_i2c_runtime_suspend(struct device *dev);

struct geni_i2c_err_log {
	int err;
@@ -1052,11 +1055,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
	int i, ret = 0, timeout = 0;

	gi2c->err = 0;
	atomic_set(&gi2c->is_xfer_in_progress, 1);

	/* Client to respect system suspend */
	if (!pm_runtime_enabled(gi2c->dev)) {
		GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev,
			"%s: System suspended\n", __func__);
		atomic_set(&gi2c->is_xfer_in_progress, 0);
		return -EACCES;
	}

@@ -1068,6 +1073,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
			pm_runtime_put_noidle(gi2c->dev);
			/* Set device in suspended since resume failed */
			pm_runtime_set_suspended(gi2c->dev);
			atomic_set(&gi2c->is_xfer_in_progress, 0);
			return ret;
		}
	}
@@ -1078,6 +1084,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		if (ret) {
			pm_runtime_mark_last_busy(gi2c->dev);
			pm_runtime_put_autosuspend(gi2c->dev);
			atomic_set(&gi2c->is_xfer_in_progress, 0);
			return ret; //Don't perform xfer is cancel failed
		}
	}
@@ -1268,7 +1275,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		pm_runtime_mark_last_busy(gi2c->dev);
		pm_runtime_put_autosuspend(gi2c->dev);
	}

	atomic_set(&gi2c->is_xfer_in_progress, 0);
	gi2c->cur = NULL;
	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
		"i2c txn ret:%d, num:%d, err:%d\n", ret, num, gi2c->err);
@@ -1476,10 +1483,10 @@ static int geni_i2c_probe(struct platform_device *pdev)
		return ret;
	}

	atomic_set(&gi2c->is_xfer_in_progress, 0);
	snprintf(boot_marker, sizeof(boot_marker),
		 "M - DRIVER GENI_I2C_%d Ready", gi2c->adap.nr);
	place_marker(boot_marker);

	dev_info(gi2c->dev, "I2C probed\n");
	return 0;
}
@@ -1489,6 +1496,33 @@ static int geni_i2c_remove(struct platform_device *pdev)
	struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
	int i;

	if (atomic_read(&gi2c->is_xfer_in_progress)) {
		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
			    "%s: Xfer is in progress\n", __func__);
		return -EBUSY;
	}

	if (!pm_runtime_status_suspended(gi2c->dev)) {
		if (geni_i2c_runtime_suspend(gi2c->dev))
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				    "%s: runtime suspend failed\n", __func__);
	}

	if (gi2c->se_mode == GSI_ONLY) {
		if (gi2c->tx_c) {
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				    "%s: clearing tx dma resource\n", __func__);
			dma_release_channel(gi2c->tx_c);
		}
		if (gi2c->rx_c) {
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				    "%s: clearing rx dma resource\n", __func__);
			dma_release_channel(gi2c->rx_c);
		}
	}

	pm_runtime_put_noidle(gi2c->dev);
	pm_runtime_set_suspended(gi2c->dev);
	pm_runtime_disable(gi2c->dev);
	i2c_del_adapter(&gi2c->adap);

@@ -1594,6 +1628,19 @@ static int geni_i2c_suspend_late(struct device *device)
	int ret;

	GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__);

	if (atomic_read(&gi2c->is_xfer_in_progress)) {
		if (!pm_runtime_status_suspended(gi2c->dev)) {
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
				    ":%s: runtime PM is active\n", __func__);
			return -EBUSY;
		}
		GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
			    "%s System suspend not allowed while xfer in progress\n",
			    __func__);
		return -EBUSY;
	}

	/* Make sure no transactions are pending */
	ret = i2c_trylock_bus(&gi2c->adap, I2C_LOCK_SEGMENT);
	if (!ret) {