--- /dev/null
+From 1e8aad01d355754c5ec31df0bc8297af773c77da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Mar 2023 08:39:38 +0100
+Subject: backlight: led_bl: Convert to platform remove callback returning void
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit c4c4fa57fd3cc00020152baa169337521f90b2ad ]
+
+The .remove() callback for a platform driver returns an int which makes
+many driver authors wrongly assume it's possible to do error handling by
+returning an error code. However the value returned is (mostly) ignored
+and this typically results in resource leaks. To improve here there is a
+quest to make the remove callback return void. In the first step of this
+quest all drivers are converted to .remove_new() which already returns
+void.
+
+Trivially convert this driver from always returning zero in the remove
+callback to the void returning variant.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Link: https://lore.kernel.org/r/20230308073945.2336302-7-u.kleine-koenig@pengutronix.de
+Stable-dep-of: 276822a00db3 ("backlight: led_bl: Hold led_access lock when calling led_sysfs_disable()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/backlight/led_bl.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c
+index f54d256e2d548..a1b6a2ad73a07 100644
+--- a/drivers/video/backlight/led_bl.c
++++ b/drivers/video/backlight/led_bl.c
+@@ -217,7 +217,7 @@ static int led_bl_probe(struct platform_device *pdev)
+ return 0;
+ }
+
+-static int led_bl_remove(struct platform_device *pdev)
++static void led_bl_remove(struct platform_device *pdev)
+ {
+ struct led_bl_data *priv = platform_get_drvdata(pdev);
+ struct backlight_device *bl = priv->bl_dev;
+@@ -228,8 +228,6 @@ static int led_bl_remove(struct platform_device *pdev)
+ led_bl_power_off(priv);
+ for (i = 0; i < priv->nb_leds; i++)
+ led_sysfs_enable(priv->leds[i]);
+-
+- return 0;
+ }
+
+ static const struct of_device_id led_bl_of_match[] = {
+@@ -245,7 +243,7 @@ static struct platform_driver led_bl_driver = {
+ .of_match_table = of_match_ptr(led_bl_of_match),
+ },
+ .probe = led_bl_probe,
+- .remove = led_bl_remove,
++ .remove_new = led_bl_remove,
+ };
+
+ module_platform_driver(led_bl_driver);
+--
+2.39.5
+
--- /dev/null
+From f52c59ee0d0e00936d200fa5fa2c7052ec019397 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 10:19:14 +0100
+Subject: backlight: led_bl: Hold led_access lock when calling
+ led_sysfs_disable()
+
+From: Herve Codina <herve.codina@bootlin.com>
+
+[ Upstream commit 276822a00db3c1061382b41e72cafc09d6a0ec30 ]
+
+Lockdep detects the following issue on led-backlight removal:
+ [ 142.315935] ------------[ cut here ]------------
+ [ 142.315954] WARNING: CPU: 2 PID: 292 at drivers/leds/led-core.c:455 led_sysfs_enable+0x54/0x80
+ ...
+ [ 142.500725] Call trace:
+ [ 142.503176] led_sysfs_enable+0x54/0x80 (P)
+ [ 142.507370] led_bl_remove+0x80/0xa8 [led_bl]
+ [ 142.511742] platform_remove+0x30/0x58
+ [ 142.515501] device_remove+0x54/0x90
+ ...
+
+Indeed, led_sysfs_enable() has to be called with the led_access
+lock held.
+
+Hold the lock when calling led_sysfs_disable().
+
+Fixes: ae232e45acf9 ("backlight: add led-backlight driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Herve Codina <herve.codina@bootlin.com>
+Link: https://lore.kernel.org/r/20250122091914.309533-1-herve.codina@bootlin.com
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/video/backlight/led_bl.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/video/backlight/led_bl.c b/drivers/video/backlight/led_bl.c
+index a1b6a2ad73a07..589dae9ebb638 100644
+--- a/drivers/video/backlight/led_bl.c
++++ b/drivers/video/backlight/led_bl.c
+@@ -226,8 +226,11 @@ static void led_bl_remove(struct platform_device *pdev)
+ backlight_device_unregister(bl);
+
+ led_bl_power_off(priv);
+- for (i = 0; i < priv->nb_leds; i++)
++ for (i = 0; i < priv->nb_leds; i++) {
++ mutex_lock(&priv->leds[i]->led_access);
+ led_sysfs_enable(priv->leds[i]);
++ mutex_unlock(&priv->leds[i]->led_access);
++ }
+ }
+
+ static const struct of_device_id led_bl_of_match[] = {
+--
+2.39.5
+
--- /dev/null
+From 94b2f11a89b3370e68571e93cd3a557cc78d3fa9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Mar 2025 17:28:58 +0300
+Subject: cifs: avoid NULL pointer dereference in dbg call
+
+From: Alexandra Diupina <adiupina@astralinux.ru>
+
+[ Upstream commit b4885bd5935bb26f0a414ad55679a372e53f9b9b ]
+
+cifs_server_dbg() implies server to be non-NULL so
+move call under condition to avoid NULL pointer dereference.
+
+Found by Linux Verification Center (linuxtesting.org) with SVACE.
+
+Fixes: e79b0332ae06 ("cifs: ignore cached share root handle closing errors")
+Cc: stable@vger.kernel.org
+Signed-off-by: Alexandra Diupina <adiupina@astralinux.ru>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/smb2misc.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
+index d21b27e68f2a8..c0b80ba8875af 100644
+--- a/fs/cifs/smb2misc.c
++++ b/fs/cifs/smb2misc.c
+@@ -809,11 +809,12 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
+ WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative");
+ spin_unlock(&cifs_tcp_ses_lock);
+
+- if (tcon->ses)
++ if (tcon->ses) {
+ server = tcon->ses->server;
+-
+- cifs_server_dbg(FYI, "tid=0x%x: tcon is closing, skipping async close retry of fid %llu %llu\n",
+- tcon->tid, persistent_fid, volatile_fid);
++ cifs_server_dbg(FYI,
++ "tid=0x%x: tcon is closing, skipping async close retry of fid %llu %llu\n",
++ tcon->tid, persistent_fid, volatile_fid);
++ }
+
+ return 0;
+ }
+--
+2.39.5
+
--- /dev/null
+From ca33e943102697ae4996cb90123cd0fdfdb488ba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 May 2022 11:41:04 -0300
+Subject: cifs: print TIDs as hex
+
+From: Enzo Matsumiya <ematsumiya@suse.de>
+
+[ Upstream commit 71081e7ac16c93acdd18afa65daa468620bb1b64 ]
+
+Makes these debug messages easier to read
+
+Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
+Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: b4885bd5935b ("cifs: avoid NULL pointer dereference in dbg call")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/connect.c | 2 +-
+ fs/cifs/smb2misc.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index a3c0e6a4e4847..2c0522d97e037 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -2770,7 +2770,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info)
+ goto out;
+ }
+
+- cifs_dbg(FYI, "IPC tcon rc = %d ipc tid = %d\n", rc, tcon->tid);
++ cifs_dbg(FYI, "IPC tcon rc=%d ipc tid=0x%x\n", rc, tcon->tid);
+
+ ses->tcon_ipc = tcon;
+ out:
+diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
+index 64887856331ae..d21b27e68f2a8 100644
+--- a/fs/cifs/smb2misc.c
++++ b/fs/cifs/smb2misc.c
+@@ -812,7 +812,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
+ if (tcon->ses)
+ server = tcon->ses->server;
+
+- cifs_server_dbg(FYI, "tid=%u: tcon is closing, skipping async close retry of fid %llu %llu\n",
++ cifs_server_dbg(FYI, "tid=0x%x: tcon is closing, skipping async close retry of fid %llu %llu\n",
+ tcon->tid, persistent_fid, volatile_fid);
+
+ return 0;
+--
+2.39.5
+
--- /dev/null
+From 5cae0e026c8b364f338819cb26b34cb3ecc51fad Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Nov 2020 13:46:10 +0100
+Subject: driver core: platform: change logic implementing
+ platform_driver_probe
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 16085668eacdc56c46652d0f3bfef81ecace57de ]
+
+Instead of overwriting the core driver's probe function handle probing
+devices for drivers loaded by platform_driver_probe() in the platform
+driver probe function.
+
+The intended goal is to not have to change the probe function to
+simplify converting the platform bus to use bus functions.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Link: https://lore.kernel.org/r/20201119124611.2573057-2-u.kleine-koenig@pengutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 276822a00db3 ("backlight: led_bl: Hold led_access lock when calling led_sysfs_disable()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/platform.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index fa023cf80dc48..16426eb934632 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -743,12 +743,25 @@ struct platform_device *platform_device_register_full(
+ }
+ EXPORT_SYMBOL_GPL(platform_device_register_full);
+
++static int platform_probe_fail(struct platform_device *pdev);
++
+ static int platform_drv_probe(struct device *_dev)
+ {
+ struct platform_driver *drv = to_platform_driver(_dev->driver);
+ struct platform_device *dev = to_platform_device(_dev);
+ int ret;
+
++ /*
++ * A driver registered using platform_driver_probe() cannot be bound
++ * again later because the probe function usually lives in __init code
++ * and so is gone. For these drivers .probe is set to
++ * platform_probe_fail in __platform_driver_probe(). Don't even
++ * prepare clocks and PM domains for these to match the traditional
++ * behaviour.
++ */
++ if (unlikely(drv->probe == platform_probe_fail))
++ return -ENXIO;
++
+ ret = of_clk_set_defaults(_dev->of_node, false);
+ if (ret < 0)
+ return ret;
+@@ -822,7 +835,7 @@ void platform_driver_unregister(struct platform_driver *drv)
+ }
+ EXPORT_SYMBOL_GPL(platform_driver_unregister);
+
+-static int platform_drv_probe_fail(struct device *_dev)
++static int platform_probe_fail(struct platform_device *pdev)
+ {
+ return -ENXIO;
+ }
+@@ -887,10 +900,9 @@ int __init_or_module __platform_driver_probe(struct platform_driver *drv,
+ * new devices fail.
+ */
+ spin_lock(&drv->driver.bus->p->klist_drivers.k_lock);
+- drv->probe = NULL;
++ drv->probe = platform_probe_fail;
+ if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
+ retval = -ENODEV;
+- drv->driver.probe = platform_drv_probe_fail;
+ spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock);
+
+ if (code != retval)
+--
+2.39.5
+
--- /dev/null
+From be789066e7a8cf1d42fae45038e28a7663cbc213 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 7 Feb 2021 22:15:37 +0100
+Subject: driver core: platform: Emit a warning if a remove callback returned
+ non-zero
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <uwe@kleine-koenig.org>
+
+[ Upstream commit e5e1c209788138f33ca6558bf9f572f6904f486d ]
+
+The driver core ignores the return value of a bus' remove callback. However
+a driver returning an error code is a hint that there is a problem,
+probably a driver author who expects that returning e.g. -EBUSY has any
+effect.
+
+The right thing to do would be to make struct platform_driver::remove()
+return void. With the immense number of platform drivers this is however a
+big quest and I hope to prevent at least a few new drivers that return an
+error code here.
+
+Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
+Link: https://lore.kernel.org/r/20210207211537.19992-1-uwe@kleine-koenig.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 276822a00db3 ("backlight: led_bl: Hold led_access lock when calling led_sysfs_disable()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/platform.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index 90166535a5c05..d0b15cbab0ff0 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -1305,13 +1305,16 @@ static int platform_remove(struct device *_dev)
+ {
+ struct platform_driver *drv = to_platform_driver(_dev->driver);
+ struct platform_device *dev = to_platform_device(_dev);
+- int ret = 0;
+
+- if (drv->remove)
+- ret = drv->remove(dev);
++ if (drv->remove) {
++ int ret = drv->remove(dev);
++
++ if (ret)
++ dev_warn(_dev, "remove callback returned a non-zero value. This will be ignored.\n");
++ }
+ dev_pm_domain_detach(_dev, true);
+
+- return ret;
++ return 0;
+ }
+
+ static void platform_shutdown(struct device *_dev)
+--
+2.39.5
+
--- /dev/null
+From 755c0725a3eaa804db5be07cd930b3d0e59648fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Nov 2020 13:46:09 +0100
+Subject: driver core: platform: reorder functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit e21d740a3fe5ad2db7b5f5c2331fe2b713b1edba ]
+
+This way all callbacks and structures used to initialize
+platform_bus_type are defined just before platform_bus_type and in the
+same order. Also move platform_drv_probe_fail just before it's only
+user.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Link: https://lore.kernel.org/r/20201119124611.2573057-1-u.kleine-koenig@pengutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 276822a00db3 ("backlight: led_bl: Hold led_access lock when calling led_sysfs_disable()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/platform.c | 293 ++++++++++++++++++++--------------------
+ 1 file changed, 147 insertions(+), 146 deletions(-)
+
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index 647066229fec3..fa023cf80dc48 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -772,11 +772,6 @@ static int platform_drv_probe(struct device *_dev)
+ return ret;
+ }
+
+-static int platform_drv_probe_fail(struct device *_dev)
+-{
+- return -ENXIO;
+-}
+-
+ static int platform_drv_remove(struct device *_dev)
+ {
+ struct platform_driver *drv = to_platform_driver(_dev->driver);
+@@ -827,6 +822,11 @@ void platform_driver_unregister(struct platform_driver *drv)
+ }
+ EXPORT_SYMBOL_GPL(platform_driver_unregister);
+
++static int platform_drv_probe_fail(struct device *_dev)
++{
++ return -ENXIO;
++}
++
+ /**
+ * __platform_driver_probe - register driver for non-hotpluggable device
+ * @drv: platform driver structure
+@@ -1017,109 +1017,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers,
+ }
+ EXPORT_SYMBOL_GPL(platform_unregister_drivers);
+
+-/* modalias support enables more hands-off userspace setup:
+- * (a) environment variable lets new-style hotplug events work once system is
+- * fully running: "modprobe $MODALIAS"
+- * (b) sysfs attribute lets new-style coldplug recover from hotplug events
+- * mishandled before system is fully running: "modprobe $(cat modalias)"
+- */
+-static ssize_t modalias_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- int len;
+-
+- len = of_device_modalias(dev, buf, PAGE_SIZE);
+- if (len != -ENODEV)
+- return len;
+-
+- len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
+- if (len != -ENODEV)
+- return len;
+-
+- return sysfs_emit(buf, "platform:%s\n", pdev->name);
+-}
+-static DEVICE_ATTR_RO(modalias);
+-
+-static ssize_t driver_override_store(struct device *dev,
+- struct device_attribute *attr,
+- const char *buf, size_t count)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- int ret;
+-
+- ret = driver_set_override(dev, &pdev->driver_override, buf, count);
+- if (ret)
+- return ret;
+-
+- return count;
+-}
+-
+-static ssize_t driver_override_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- ssize_t len;
+-
+- device_lock(dev);
+- len = sysfs_emit(buf, "%s\n", pdev->driver_override);
+- device_unlock(dev);
+-
+- return len;
+-}
+-static DEVICE_ATTR_RW(driver_override);
+-
+-static ssize_t numa_node_show(struct device *dev,
+- struct device_attribute *attr, char *buf)
+-{
+- return sysfs_emit(buf, "%d\n", dev_to_node(dev));
+-}
+-static DEVICE_ATTR_RO(numa_node);
+-
+-static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a,
+- int n)
+-{
+- struct device *dev = container_of(kobj, typeof(*dev), kobj);
+-
+- if (a == &dev_attr_numa_node.attr &&
+- dev_to_node(dev) == NUMA_NO_NODE)
+- return 0;
+-
+- return a->mode;
+-}
+-
+-static struct attribute *platform_dev_attrs[] = {
+- &dev_attr_modalias.attr,
+- &dev_attr_numa_node.attr,
+- &dev_attr_driver_override.attr,
+- NULL,
+-};
+-
+-static struct attribute_group platform_dev_group = {
+- .attrs = platform_dev_attrs,
+- .is_visible = platform_dev_attrs_visible,
+-};
+-__ATTRIBUTE_GROUPS(platform_dev);
+-
+-static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- int rc;
+-
+- /* Some devices have extra OF data and an OF-style MODALIAS */
+- rc = of_device_uevent_modalias(dev, env);
+- if (rc != -ENODEV)
+- return rc;
+-
+- rc = acpi_device_uevent_modalias(dev, env);
+- if (rc != -ENODEV)
+- return rc;
+-
+- add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
+- pdev->name);
+- return 0;
+-}
+-
+ static const struct platform_device_id *platform_match_id(
+ const struct platform_device_id *id,
+ struct platform_device *pdev)
+@@ -1134,44 +1031,6 @@ static const struct platform_device_id *platform_match_id(
+ return NULL;
+ }
+
+-/**
+- * platform_match - bind platform device to platform driver.
+- * @dev: device.
+- * @drv: driver.
+- *
+- * Platform device IDs are assumed to be encoded like this:
+- * "<name><instance>", where <name> is a short description of the type of
+- * device, like "pci" or "floppy", and <instance> is the enumerated
+- * instance of the device, like '0' or '42'. Driver IDs are simply
+- * "<name>". So, extract the <name> from the platform_device structure,
+- * and compare it against the name of the driver. Return whether they match
+- * or not.
+- */
+-static int platform_match(struct device *dev, struct device_driver *drv)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- struct platform_driver *pdrv = to_platform_driver(drv);
+-
+- /* When driver_override is set, only bind to the matching driver */
+- if (pdev->driver_override)
+- return !strcmp(pdev->driver_override, drv->name);
+-
+- /* Attempt an OF style match first */
+- if (of_driver_match_device(dev, drv))
+- return 1;
+-
+- /* Then try ACPI style match */
+- if (acpi_driver_match_device(dev, drv))
+- return 1;
+-
+- /* Then try to match against the id table */
+- if (pdrv->id_table)
+- return platform_match_id(pdrv->id_table, pdev) != NULL;
+-
+- /* fall-back to driver name match */
+- return (strcmp(pdev->name, drv->name) == 0);
+-}
+-
+ #ifdef CONFIG_PM_SLEEP
+
+ static int platform_legacy_suspend(struct device *dev, pm_message_t mesg)
+@@ -1316,6 +1175,148 @@ int platform_pm_restore(struct device *dev)
+
+ #endif /* CONFIG_HIBERNATE_CALLBACKS */
+
++/* modalias support enables more hands-off userspace setup:
++ * (a) environment variable lets new-style hotplug events work once system is
++ * fully running: "modprobe $MODALIAS"
++ * (b) sysfs attribute lets new-style coldplug recover from hotplug events
++ * mishandled before system is fully running: "modprobe $(cat modalias)"
++ */
++static ssize_t modalias_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ int len;
++
++ len = of_device_modalias(dev, buf, PAGE_SIZE);
++ if (len != -ENODEV)
++ return len;
++
++ len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
++ if (len != -ENODEV)
++ return len;
++
++ return sysfs_emit(buf, "platform:%s\n", pdev->name);
++}
++static DEVICE_ATTR_RO(modalias);
++
++static ssize_t numa_node_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sysfs_emit(buf, "%d\n", dev_to_node(dev));
++}
++static DEVICE_ATTR_RO(numa_node);
++
++static ssize_t driver_override_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ ssize_t len;
++
++ device_lock(dev);
++ len = sysfs_emit(buf, "%s\n", pdev->driver_override);
++ device_unlock(dev);
++
++ return len;
++}
++
++static ssize_t driver_override_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ int ret;
++
++ ret = driver_set_override(dev, &pdev->driver_override, buf, count);
++ if (ret)
++ return ret;
++
++ return count;
++}
++static DEVICE_ATTR_RW(driver_override);
++
++static struct attribute *platform_dev_attrs[] = {
++ &dev_attr_modalias.attr,
++ &dev_attr_numa_node.attr,
++ &dev_attr_driver_override.attr,
++ NULL,
++};
++
++static umode_t platform_dev_attrs_visible(struct kobject *kobj, struct attribute *a,
++ int n)
++{
++ struct device *dev = container_of(kobj, typeof(*dev), kobj);
++
++ if (a == &dev_attr_numa_node.attr &&
++ dev_to_node(dev) == NUMA_NO_NODE)
++ return 0;
++
++ return a->mode;
++}
++
++static struct attribute_group platform_dev_group = {
++ .attrs = platform_dev_attrs,
++ .is_visible = platform_dev_attrs_visible,
++};
++__ATTRIBUTE_GROUPS(platform_dev);
++
++
++/**
++ * platform_match - bind platform device to platform driver.
++ * @dev: device.
++ * @drv: driver.
++ *
++ * Platform device IDs are assumed to be encoded like this:
++ * "<name><instance>", where <name> is a short description of the type of
++ * device, like "pci" or "floppy", and <instance> is the enumerated
++ * instance of the device, like '0' or '42'. Driver IDs are simply
++ * "<name>". So, extract the <name> from the platform_device structure,
++ * and compare it against the name of the driver. Return whether they match
++ * or not.
++ */
++static int platform_match(struct device *dev, struct device_driver *drv)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct platform_driver *pdrv = to_platform_driver(drv);
++
++ /* When driver_override is set, only bind to the matching driver */
++ if (pdev->driver_override)
++ return !strcmp(pdev->driver_override, drv->name);
++
++ /* Attempt an OF style match first */
++ if (of_driver_match_device(dev, drv))
++ return 1;
++
++ /* Then try ACPI style match */
++ if (acpi_driver_match_device(dev, drv))
++ return 1;
++
++ /* Then try to match against the id table */
++ if (pdrv->id_table)
++ return platform_match_id(pdrv->id_table, pdev) != NULL;
++
++ /* fall-back to driver name match */
++ return (strcmp(pdev->name, drv->name) == 0);
++}
++
++static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ int rc;
++
++ /* Some devices have extra OF data and an OF-style MODALIAS */
++ rc = of_device_uevent_modalias(dev, env);
++ if (rc != -ENODEV)
++ return rc;
++
++ rc = acpi_device_uevent_modalias(dev, env);
++ if (rc != -ENODEV)
++ return rc;
++
++ add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,
++ pdev->name);
++ return 0;
++}
++
+ int platform_dma_configure(struct device *dev)
+ {
+ enum dev_dma_attr attr;
+--
+2.39.5
+
--- /dev/null
+From 9d1ddcb33799b6b3c278d2c440ec242db06cc644 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Nov 2020 13:46:11 +0100
+Subject: driver core: platform: use bus_type functions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 9c30921fe7994907e0b3e0637b2c8c0fc4b5171f ]
+
+This works towards the goal mentioned in 2006 in commit 594c8281f905
+("[PATCH] Add bus_type probe, remove, shutdown methods.").
+
+The functions are moved to where the other bus_type functions are
+defined and renamed to match the already established naming scheme.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Link: https://lore.kernel.org/r/20201119124611.2573057-3-u.kleine-koenig@pengutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 276822a00db3 ("backlight: led_bl: Hold led_access lock when calling led_sysfs_disable()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/platform.c | 132 ++++++++++++++++++++--------------------
+ 1 file changed, 65 insertions(+), 67 deletions(-)
+
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index 16426eb934632..90166535a5c05 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -743,70 +743,6 @@ struct platform_device *platform_device_register_full(
+ }
+ EXPORT_SYMBOL_GPL(platform_device_register_full);
+
+-static int platform_probe_fail(struct platform_device *pdev);
+-
+-static int platform_drv_probe(struct device *_dev)
+-{
+- struct platform_driver *drv = to_platform_driver(_dev->driver);
+- struct platform_device *dev = to_platform_device(_dev);
+- int ret;
+-
+- /*
+- * A driver registered using platform_driver_probe() cannot be bound
+- * again later because the probe function usually lives in __init code
+- * and so is gone. For these drivers .probe is set to
+- * platform_probe_fail in __platform_driver_probe(). Don't even
+- * prepare clocks and PM domains for these to match the traditional
+- * behaviour.
+- */
+- if (unlikely(drv->probe == platform_probe_fail))
+- return -ENXIO;
+-
+- ret = of_clk_set_defaults(_dev->of_node, false);
+- if (ret < 0)
+- return ret;
+-
+- ret = dev_pm_domain_attach(_dev, true);
+- if (ret)
+- goto out;
+-
+- if (drv->probe) {
+- ret = drv->probe(dev);
+- if (ret)
+- dev_pm_domain_detach(_dev, true);
+- }
+-
+-out:
+- if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
+- dev_warn(_dev, "probe deferral not supported\n");
+- ret = -ENXIO;
+- }
+-
+- return ret;
+-}
+-
+-static int platform_drv_remove(struct device *_dev)
+-{
+- struct platform_driver *drv = to_platform_driver(_dev->driver);
+- struct platform_device *dev = to_platform_device(_dev);
+- int ret = 0;
+-
+- if (drv->remove)
+- ret = drv->remove(dev);
+- dev_pm_domain_detach(_dev, true);
+-
+- return ret;
+-}
+-
+-static void platform_drv_shutdown(struct device *_dev)
+-{
+- struct platform_driver *drv = to_platform_driver(_dev->driver);
+- struct platform_device *dev = to_platform_device(_dev);
+-
+- if (drv->shutdown)
+- drv->shutdown(dev);
+-}
+-
+ /**
+ * __platform_driver_register - register a driver for platform-level devices
+ * @drv: platform driver structure
+@@ -817,9 +753,6 @@ int __platform_driver_register(struct platform_driver *drv,
+ {
+ drv->driver.owner = owner;
+ drv->driver.bus = &platform_bus_type;
+- drv->driver.probe = platform_drv_probe;
+- drv->driver.remove = platform_drv_remove;
+- drv->driver.shutdown = platform_drv_shutdown;
+
+ return driver_register(&drv->driver);
+ }
+@@ -1329,6 +1262,68 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
+ return 0;
+ }
+
++static int platform_probe(struct device *_dev)
++{
++ struct platform_driver *drv = to_platform_driver(_dev->driver);
++ struct platform_device *dev = to_platform_device(_dev);
++ int ret;
++
++ /*
++ * A driver registered using platform_driver_probe() cannot be bound
++ * again later because the probe function usually lives in __init code
++ * and so is gone. For these drivers .probe is set to
++ * platform_probe_fail in __platform_driver_probe(). Don't even prepare
++ * clocks and PM domains for these to match the traditional behaviour.
++ */
++ if (unlikely(drv->probe == platform_probe_fail))
++ return -ENXIO;
++
++ ret = of_clk_set_defaults(_dev->of_node, false);
++ if (ret < 0)
++ return ret;
++
++ ret = dev_pm_domain_attach(_dev, true);
++ if (ret)
++ goto out;
++
++ if (drv->probe) {
++ ret = drv->probe(dev);
++ if (ret)
++ dev_pm_domain_detach(_dev, true);
++ }
++
++out:
++ if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
++ dev_warn(_dev, "probe deferral not supported\n");
++ ret = -ENXIO;
++ }
++
++ return ret;
++}
++
++static int platform_remove(struct device *_dev)
++{
++ struct platform_driver *drv = to_platform_driver(_dev->driver);
++ struct platform_device *dev = to_platform_device(_dev);
++ int ret = 0;
++
++ if (drv->remove)
++ ret = drv->remove(dev);
++ dev_pm_domain_detach(_dev, true);
++
++ return ret;
++}
++
++static void platform_shutdown(struct device *_dev)
++{
++ struct platform_driver *drv = to_platform_driver(_dev->driver);
++ struct platform_device *dev = to_platform_device(_dev);
++
++ if (drv->shutdown)
++ drv->shutdown(dev);
++}
++
++
+ int platform_dma_configure(struct device *dev)
+ {
+ enum dev_dma_attr attr;
+@@ -1355,6 +1350,9 @@ struct bus_type platform_bus_type = {
+ .dev_groups = platform_dev_groups,
+ .match = platform_match,
+ .uevent = platform_uevent,
++ .probe = platform_probe,
++ .remove = platform_remove,
++ .shutdown = platform_shutdown,
+ .dma_configure = platform_dma_configure,
+ .pm = &platform_dev_pm_ops,
+ };
+--
+2.39.5
+
--- /dev/null
+From a9c47f8b5efe42ca3ceb81a9e8d70006ba9ca05f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Nov 2020 13:49:17 +0000
+Subject: drm/amd/amdgpu/amdgpu_vram_mgr: Add missing descriptions for 'dev'
+ and 'dir'
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Lee Jones <lee.jones@linaro.org>
+
+[ Upstream commit 2c8645b7a6974b33744b677e9ddc89650776af46 ]
+
+Fixes the following W=1 kernel build warning(s):
+
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c:648: warning: Function parameter or member 'dev' not described in 'amdgpu_vram_mgr_free_sgt'
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c:648: warning: Function parameter or member 'dir' not described in 'amdgpu_vram_mgr_free_sgt'
+
+Cc: Alex Deucher <alexander.deucher@amd.com>
+Cc: "Christian König" <christian.koenig@amd.com>
+Cc: David Airlie <airlied@linux.ie>
+Cc: Daniel Vetter <daniel@ffwll.ch>
+Cc: amd-gfx@lists.freedesktop.org
+Cc: dri-devel@lists.freedesktop.org
+Signed-off-by: Lee Jones <lee.jones@linaro.org>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: c0dd8a9253fa ("drm/amdgpu/dma_buf: fix page_link check")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+index 0c6b7c5ecfec8..2c3a94e939bab 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+@@ -531,6 +531,8 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
+ * amdgpu_vram_mgr_alloc_sgt - allocate and fill a sg table
+ *
+ * @adev: amdgpu device pointer
++ * @dev: device pointer
++ * @dir: data direction of resource to unmap
+ * @sgt: sg table to free
+ *
+ * Free a previously allocate sg table.
+--
+2.39.5
+
--- /dev/null
+From 7e694c1f9f11eed69047faa76f75378475bcc265 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Apr 2025 15:18:25 +0100
+Subject: drm/amdgpu/dma_buf: fix page_link check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Matthew Auld <matthew.auld@intel.com>
+
+[ Upstream commit c0dd8a9253fadfb8e5357217d085f1989da4ef0a ]
+
+The page_link lower bits of the first sg could contain something like
+SG_END, if we are mapping a single VRAM page or contiguous blob which
+fits into one sg entry. Rather pull out the struct page, and use that in
+our check to know if we mapped struct pages vs VRAM.
+
+Fixes: f44ffd677fb3 ("drm/amdgpu: add support for exporting VRAM using DMA-buf v3")
+Signed-off-by: Matthew Auld <matthew.auld@intel.com>
+Cc: Christian König <christian.koenig@amd.com>
+Cc: amd-gfx@lists.freedesktop.org
+Cc: <stable@vger.kernel.org> # v5.8+
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+index bbbacc7b6c463..e4d0a9377e712 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+@@ -357,7 +357,7 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach,
+ struct sg_table *sgt,
+ enum dma_data_direction dir)
+ {
+- if (sgt->sgl->page_link) {
++ if (sg_page(sgt->sgl)) {
+ dma_unmap_sgtable(attach->dev, sgt, dir, 0);
+ sg_free_table(sgt);
+ kfree(sgt);
+--
+2.39.5
+
--- /dev/null
+From 09a1b6ca7c7d9c07c702479646a0a8cfa2329e11 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Feb 2021 20:48:06 -0600
+Subject: drm/amdgpu: Remove amdgpu_device arg from free_sgt api (v2)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ramesh Errabolu <Ramesh.Errabolu@amd.com>
+
+[ Upstream commit 5392b2af97dc5802991f953eb2687e538da4688c ]
+
+Currently callers have to provide handle of amdgpu_device,
+which is not used by the implementation. It is unlikely this
+parameter will become useful in future, thus removing it
+
+v2: squash in unused variable fix
+
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Ramesh Errabolu <Ramesh.Errabolu@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: c0dd8a9253fa ("drm/amdgpu/dma_buf: fix page_link check")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c | 7 +------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h | 3 +--
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c | 4 +---
+ 3 files changed, 3 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+index e93ccdc5faf4e..bbbacc7b6c463 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+@@ -357,17 +357,12 @@ static void amdgpu_dma_buf_unmap(struct dma_buf_attachment *attach,
+ struct sg_table *sgt,
+ enum dma_data_direction dir)
+ {
+- struct dma_buf *dma_buf = attach->dmabuf;
+- struct drm_gem_object *obj = dma_buf->priv;
+- struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
+- struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
+-
+ if (sgt->sgl->page_link) {
+ dma_unmap_sgtable(attach->dev, sgt, dir, 0);
+ sg_free_table(sgt);
+ kfree(sgt);
+ } else {
+- amdgpu_vram_mgr_free_sgt(adev, attach->dev, dir, sgt);
++ amdgpu_vram_mgr_free_sgt(attach->dev, dir, sgt);
+ }
+ }
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+index a87951b2f06dd..bd873b1b760cf 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
+@@ -113,8 +113,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
+ struct device *dev,
+ enum dma_data_direction dir,
+ struct sg_table **sgt);
+-void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
+- struct device *dev,
++void amdgpu_vram_mgr_free_sgt(struct device *dev,
+ enum dma_data_direction dir,
+ struct sg_table *sgt);
+ uint64_t amdgpu_vram_mgr_usage(struct ttm_resource_manager *man);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+index 2c3a94e939bab..ad72db21b8d62 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
+@@ -530,15 +530,13 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
+ /**
+ * amdgpu_vram_mgr_alloc_sgt - allocate and fill a sg table
+ *
+- * @adev: amdgpu device pointer
+ * @dev: device pointer
+ * @dir: data direction of resource to unmap
+ * @sgt: sg table to free
+ *
+ * Free a previously allocate sg table.
+ */
+-void amdgpu_vram_mgr_free_sgt(struct amdgpu_device *adev,
+- struct device *dev,
++void amdgpu_vram_mgr_free_sgt(struct device *dev,
+ enum dma_data_direction dir,
+ struct sg_table *sgt)
+ {
+--
+2.39.5
+
--- /dev/null
+From 5d51c142998785ea086034e7f5fabba2331aa344 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Mar 2025 18:00:29 -0300
+Subject: iio: adc: ad7768-1: Fix conversion result sign
+
+From: Sergiu Cuciurean <sergiu.cuciurean@analog.com>
+
+[ Upstream commit 8236644f5ecb180e80ad92d691c22bc509b747bb ]
+
+The ad7768-1 ADC output code is two's complement, meaning that the voltage
+conversion result is a signed value.. Since the value is a 24 bit one,
+stored in a 32 bit variable, the sign should be extended in order to get
+the correct representation.
+
+Also the channel description has been updated to signed representation,
+to match the ADC specifications.
+
+Fixes: a5f8c7da3dbe ("iio: adc: Add AD7768-1 ADC basic support")
+Reviewed-by: David Lechner <dlechner@baylibre.com>
+Reviewed-by: Marcelo Schmitt <marcelo.schmitt@analog.com>
+Signed-off-by: Sergiu Cuciurean <sergiu.cuciurean@analog.com>
+Signed-off-by: Jonathan Santos <Jonathan.Santos@analog.com>
+Cc: <Stable@vger.kernel.org>
+Link: https://patch.msgid.link/505994d3b71c2aa38ba714d909a68e021f12124c.1741268122.git.Jonathan.Santos@analog.com
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/ad7768-1.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
+index c409b498fc313..2445ebc551dd1 100644
+--- a/drivers/iio/adc/ad7768-1.c
++++ b/drivers/iio/adc/ad7768-1.c
+@@ -142,7 +142,7 @@ static const struct iio_chan_spec ad7768_channels[] = {
+ .channel = 0,
+ .scan_index = 0,
+ .scan_type = {
+- .sign = 'u',
++ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .shift = 8,
+@@ -373,7 +373,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+- *val = ret;
++ *val = sign_extend32(ret, chan->scan_type.realbits - 1);
+
+ return IIO_VAL_INT;
+
+--
+2.39.5
+
--- /dev/null
+From 33e1e987e03b89ac7f1a1aa4a8bf84efe2d7527d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Feb 2025 14:16:12 +0000
+Subject: iio: adc: ad7768-1: Move setting of val a bit later to avoid
+ unnecessary return value check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+
+[ Upstream commit 0af1c801a15225304a6328258efbf2bee245c654 ]
+
+The data used is all in local variables so there is no advantage
+in setting *val = ret with the direct mode claim held.
+Move it later to after error check.
+
+Reviewed-by: Nuno Sá <nuno.sa@analog.com>
+Link: https://patch.msgid.link/20250217141630.897334-13-jic23@kernel.org
+Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Stable-dep-of: 8236644f5ecb ("iio: adc: ad7768-1: Fix conversion result sign")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/iio/adc/ad7768-1.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
+index 4afa50e5c058a..c409b498fc313 100644
+--- a/drivers/iio/adc/ad7768-1.c
++++ b/drivers/iio/adc/ad7768-1.c
+@@ -369,12 +369,11 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
+ return ret;
+
+ ret = ad7768_scan_direct(indio_dev);
+- if (ret >= 0)
+- *val = ret;
+
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
++ *val = ret;
+
+ return IIO_VAL_INT;
+
+--
+2.39.5
+
--- /dev/null
+From d5b00259ac8d78bd8858d2e94ef40c63d7691cbf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jan 2025 13:51:30 +0300
+Subject: media: streamzap: fix race between device disconnection and urb
+ callback
+
+From: Murad Masimov <m.masimov@mt-integration.ru>
+
+[ Upstream commit f656cfbc7a293a039d6a0c7100e1c846845148c1 ]
+
+Syzkaller has reported a general protection fault at function
+ir_raw_event_store_with_filter(). This crash is caused by a NULL pointer
+dereference of dev->raw pointer, even though it is checked for NULL in
+the same function, which means there is a race condition. It occurs due
+to the incorrect order of actions in the streamzap_disconnect() function:
+rc_unregister_device() is called before usb_kill_urb(). The dev->raw
+pointer is freed and set to NULL in rc_unregister_device(), and only
+after that usb_kill_urb() waits for in-progress requests to finish.
+
+If rc_unregister_device() is called while streamzap_callback() handler is
+not finished, this can lead to accessing freed resources. Thus
+rc_unregister_device() should be called after usb_kill_urb().
+
+Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
+
+Fixes: 8e9e60640067 ("V4L/DVB: staging/lirc: port lirc_streamzap to ir-core")
+Cc: stable@vger.kernel.org
+Reported-by: syzbot+34008406ee9a31b13c73@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=34008406ee9a31b13c73
+Signed-off-by: Murad Masimov <m.masimov@mt-integration.ru>
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/rc/streamzap.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
+index cd994e27362eb..c0a48f991d9d2 100644
+--- a/drivers/media/rc/streamzap.c
++++ b/drivers/media/rc/streamzap.c
+@@ -433,8 +433,8 @@ static void streamzap_disconnect(struct usb_interface *interface)
+ if (!sz)
+ return;
+
+- rc_unregister_device(sz->rdev);
+ usb_kill_urb(sz->urb_in);
++ rc_unregister_device(sz->rdev);
+ usb_free_urb(sz->urb_in);
+ usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+
+--
+2.39.5
+
--- /dev/null
+From 6bc7009d9eadddd40c2c174b7e88d677d3a88733 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Dec 2021 22:38:20 +0100
+Subject: media: streamzap: less chatter
+
+From: Sean Young <sean@mess.org>
+
+[ Upstream commit 35088717ad24140b6ab0ec00ef357709be607526 ]
+
+Remove superfluous messages which add no information.
+
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: f656cfbc7a29 ("media: streamzap: fix race between device disconnection and urb callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/rc/streamzap.c | 20 +-------------------
+ 1 file changed, 1 insertion(+), 19 deletions(-)
+
+diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
+index b6391ad383143..e862a866b9b0f 100644
+--- a/drivers/media/rc/streamzap.c
++++ b/drivers/media/rc/streamzap.c
+@@ -26,7 +26,6 @@
+ #include <linux/usb/input.h>
+ #include <media/rc-core.h>
+
+-#define DRIVER_VERSION "1.61"
+ #define DRIVER_NAME "streamzap"
+ #define DRIVER_DESC "Streamzap Remote Control driver"
+
+@@ -281,10 +280,8 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
+ int ret;
+
+ rdev = rc_allocate_device(RC_DRIVER_IR_RAW);
+- if (!rdev) {
+- dev_err(dev, "remote dev allocation failed\n");
++ if (!rdev)
+ goto out;
+- }
+
+ usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys));
+ strlcat(sz->phys, "/input0", sizeof(sz->phys));
+@@ -324,7 +321,6 @@ static int streamzap_probe(struct usb_interface *intf,
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+ struct usb_host_interface *iface_host;
+ struct streamzap_ir *sz = NULL;
+- char buf[63], name[128] = "";
+ int retval = -ENOMEM;
+ int pipe, maxp;
+
+@@ -383,17 +379,6 @@ static int streamzap_probe(struct usb_interface *intf,
+ sz->dev = &intf->dev;
+ sz->buf_in_len = maxp;
+
+- if (usbdev->descriptor.iManufacturer
+- && usb_string(usbdev, usbdev->descriptor.iManufacturer,
+- buf, sizeof(buf)) > 0)
+- strscpy(name, buf, sizeof(name));
+-
+- if (usbdev->descriptor.iProduct
+- && usb_string(usbdev, usbdev->descriptor.iProduct,
+- buf, sizeof(buf)) > 0)
+- snprintf(name + strlen(name), sizeof(name) - strlen(name),
+- " %s", buf);
+-
+ sz->rdev = streamzap_init_rc_dev(sz);
+ if (!sz->rdev)
+ goto rc_dev_fail;
+@@ -424,9 +409,6 @@ static int streamzap_probe(struct usb_interface *intf,
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
+ dev_err(sz->dev, "urb submit failed\n");
+
+- dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
+- usbdev->bus->busnum, usbdev->devnum);
+-
+ return 0;
+
+ rc_dev_fail:
+--
+2.39.5
+
--- /dev/null
+From b3896ae1ac76c9b0870e211a28f2cdea2b7a86d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Dec 2021 18:10:36 +0100
+Subject: media: streamzap: no need for usb pid/vid in device name
+
+From: Sean Young <sean@mess.org>
+
+[ Upstream commit 7a25e6849ad73de5aa01d62da43071bc02b8530c ]
+
+The usb pid/vid can be found elsewhere, the idVendor/idProduct usb sysfs
+files for example.
+
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: f656cfbc7a29 ("media: streamzap: fix race between device disconnection and urb callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/rc/streamzap.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
+index cd4bb605a7614..b6391ad383143 100644
+--- a/drivers/media/rc/streamzap.c
++++ b/drivers/media/rc/streamzap.c
+@@ -88,7 +88,6 @@ struct streamzap_ir {
+ ktime_t signal_start;
+ bool timeout_enabled;
+
+- char name[128];
+ char phys[64];
+ };
+
+@@ -287,13 +286,10 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
+ goto out;
+ }
+
+- snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared Receiver (%04x:%04x)",
+- le16_to_cpu(sz->usbdev->descriptor.idVendor),
+- le16_to_cpu(sz->usbdev->descriptor.idProduct));
+ usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys));
+ strlcat(sz->phys, "/input0", sizeof(sz->phys));
+
+- rdev->device_name = sz->name;
++ rdev->device_name = "Streamzap PC Remote Infrared Receiver";
+ rdev->input_phys = sz->phys;
+ usb_to_input_id(sz->usbdev, &rdev->input_id);
+ rdev->dev.parent = dev;
+--
+2.39.5
+
--- /dev/null
+From 898eeec1c636914231d739ee44e005aae3bc9995 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Dec 2021 18:06:30 +0100
+Subject: media: streamzap: remove unnecessary ir_raw_event_reset and handle
+
+From: Sean Young <sean@mess.org>
+
+[ Upstream commit 4bed9306050497f49cbe77b842f0d812f4f27593 ]
+
+There is no reason to have a reset after an IR timeout.
+Calling ir_raw_event_handle() twice for the same interrupt has no
+affect.
+
+Fixes: 56b0ec30c4bc ("[media] rc/streamzap: fix reporting response times")
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: f656cfbc7a29 ("media: streamzap: fix race between device disconnection and urb callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/rc/streamzap.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
+index b6bd3cbec7c7c..cd4bb605a7614 100644
+--- a/drivers/media/rc/streamzap.c
++++ b/drivers/media/rc/streamzap.c
+@@ -215,8 +215,6 @@ static void sz_process_ir_data(struct streamzap_ir *sz, int len)
+ sz->idle = true;
+ if (sz->timeout_enabled)
+ sz_push(sz, rawir);
+- ir_raw_event_handle(sz->rdev);
+- ir_raw_event_reset(sz->rdev);
+ } else {
+ sz_push_full_space(sz, sz->buf_in[i]);
+ }
+--
+2.39.5
+
--- /dev/null
+From 40924984f233b4448773a81cb80848f9a4163eac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 6 Dec 2021 11:59:41 +0100
+Subject: media: streamzap: remove unused struct members
+
+From: Sean Young <sean@mess.org>
+
+[ Upstream commit 4df69e46c352df9bdbe859824da33428a3ce8a1d ]
+
+These struct members do not serve any purpose.
+
+Signed-off-by: Sean Young <sean@mess.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: f656cfbc7a29 ("media: streamzap: fix race between device disconnection and urb callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/rc/streamzap.c | 37 ++++++++++++++----------------------
+ 1 file changed, 14 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
+index e862a866b9b0f..cd994e27362eb 100644
+--- a/drivers/media/rc/streamzap.c
++++ b/drivers/media/rc/streamzap.c
+@@ -66,9 +66,6 @@ struct streamzap_ir {
+ struct device *dev;
+
+ /* usb */
+- struct usb_device *usbdev;
+- struct usb_interface *interface;
+- struct usb_endpoint_descriptor *endpoint;
+ struct urb *urb_in;
+
+ /* buffer & dma */
+@@ -85,7 +82,6 @@ struct streamzap_ir {
+ /* start time of signal; necessary for gap tracking */
+ ktime_t signal_last;
+ ktime_t signal_start;
+- bool timeout_enabled;
+
+ char phys[64];
+ };
+@@ -211,8 +207,7 @@ static void sz_process_ir_data(struct streamzap_ir *sz, int len)
+ .duration = sz->rdev->timeout
+ };
+ sz->idle = true;
+- if (sz->timeout_enabled)
+- sz_push(sz, rawir);
++ sz_push(sz, rawir);
+ } else {
+ sz_push_full_space(sz, sz->buf_in[i]);
+ }
+@@ -273,7 +268,8 @@ static void streamzap_callback(struct urb *urb)
+ return;
+ }
+
+-static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
++static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz,
++ struct usb_device *usbdev)
+ {
+ struct rc_dev *rdev;
+ struct device *dev = sz->dev;
+@@ -283,12 +279,12 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
+ if (!rdev)
+ goto out;
+
+- usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys));
++ usb_make_path(usbdev, sz->phys, sizeof(sz->phys));
+ strlcat(sz->phys, "/input0", sizeof(sz->phys));
+
+ rdev->device_name = "Streamzap PC Remote Infrared Receiver";
+ rdev->input_phys = sz->phys;
+- usb_to_input_id(sz->usbdev, &rdev->input_id);
++ usb_to_input_id(usbdev, &rdev->input_id);
+ rdev->dev.parent = dev;
+ rdev->priv = sz;
+ rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
+@@ -319,6 +315,7 @@ static int streamzap_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+ {
+ struct usb_device *usbdev = interface_to_usbdev(intf);
++ struct usb_endpoint_descriptor *endpoint;
+ struct usb_host_interface *iface_host;
+ struct streamzap_ir *sz = NULL;
+ int retval = -ENOMEM;
+@@ -329,9 +326,6 @@ static int streamzap_probe(struct usb_interface *intf,
+ if (!sz)
+ return -ENOMEM;
+
+- sz->usbdev = usbdev;
+- sz->interface = intf;
+-
+ /* Check to ensure endpoint information matches requirements */
+ iface_host = intf->cur_altsetting;
+
+@@ -342,22 +336,22 @@ static int streamzap_probe(struct usb_interface *intf,
+ goto free_sz;
+ }
+
+- sz->endpoint = &(iface_host->endpoint[0].desc);
+- if (!usb_endpoint_dir_in(sz->endpoint)) {
++ endpoint = &iface_host->endpoint[0].desc;
++ if (!usb_endpoint_dir_in(endpoint)) {
+ dev_err(&intf->dev, "%s: endpoint doesn't match input device 02%02x\n",
+- __func__, sz->endpoint->bEndpointAddress);
++ __func__, endpoint->bEndpointAddress);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+- if (!usb_endpoint_xfer_int(sz->endpoint)) {
++ if (!usb_endpoint_xfer_int(endpoint)) {
+ dev_err(&intf->dev, "%s: endpoint attributes don't match xfer 02%02x\n",
+- __func__, sz->endpoint->bmAttributes);
++ __func__, endpoint->bmAttributes);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+- pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress);
++ pipe = usb_rcvintpipe(usbdev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe));
+
+ if (maxp == 0) {
+@@ -379,14 +373,13 @@ static int streamzap_probe(struct usb_interface *intf,
+ sz->dev = &intf->dev;
+ sz->buf_in_len = maxp;
+
+- sz->rdev = streamzap_init_rc_dev(sz);
++ sz->rdev = streamzap_init_rc_dev(sz, usbdev);
+ if (!sz->rdev)
+ goto rc_dev_fail;
+
+ sz->idle = true;
+ sz->decoder_state = PulseSpace;
+ /* FIXME: don't yet have a way to set this */
+- sz->timeout_enabled = true;
+ sz->rdev->timeout = SZ_TIMEOUT * SZ_RESOLUTION;
+ #if 0
+ /* not yet supported, depends on patches from maxim */
+@@ -399,8 +392,7 @@ static int streamzap_probe(struct usb_interface *intf,
+
+ /* Complete final initialisations */
+ usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in,
+- maxp, (usb_complete_t)streamzap_callback,
+- sz, sz->endpoint->bInterval);
++ maxp, streamzap_callback, sz, endpoint->bInterval);
+ sz->urb_in->transfer_dma = sz->dma_in;
+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+@@ -441,7 +433,6 @@ static void streamzap_disconnect(struct usb_interface *interface)
+ if (!sz)
+ return;
+
+- sz->usbdev = NULL;
+ rc_unregister_device(sz->rdev);
+ usb_kill_urb(sz->urb_in);
+ usb_free_urb(sz->urb_in);
+--
+2.39.5
+
--- /dev/null
+From 4438dabf3e3dfa5894370f1bd66b855bc1d7d948 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Aug 2020 09:36:06 +0200
+Subject: media: venus: Create hfi platform and move vpp/vsp there
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit aa6033892b1d8ea956ce0358867806e171a620d1 ]
+
+Introduce a new hfi platform to cover differences between hfi
+versions. As a start move vpp/vsp freq data in that hfi
+platform, more platform data will come later.
+
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/venus/Makefile | 3 +-
+ drivers/media/platform/qcom/venus/core.c | 17 ------
+ drivers/media/platform/qcom/venus/core.h | 12 +---
+ drivers/media/platform/qcom/venus/helpers.c | 54 ++++++++---------
+ drivers/media/platform/qcom/venus/helpers.h | 2 +-
+ .../media/platform/qcom/venus/hfi_platform.c | 49 +++++++++++++++
+ .../media/platform/qcom/venus/hfi_platform.h | 34 +++++++++++
+ .../platform/qcom/venus/hfi_platform_v4.c | 60 +++++++++++++++++++
+ .../media/platform/qcom/venus/pm_helpers.c | 9 +--
+ drivers/media/platform/qcom/venus/vdec.c | 6 +-
+ drivers/media/platform/qcom/venus/venc.c | 6 +-
+ 11 files changed, 179 insertions(+), 73 deletions(-)
+ create mode 100644 drivers/media/platform/qcom/venus/hfi_platform.c
+ create mode 100644 drivers/media/platform/qcom/venus/hfi_platform.h
+ create mode 100644 drivers/media/platform/qcom/venus/hfi_platform_v4.c
+
+diff --git a/drivers/media/platform/qcom/venus/Makefile b/drivers/media/platform/qcom/venus/Makefile
+index dfc6368657091..09ebf46716925 100644
+--- a/drivers/media/platform/qcom/venus/Makefile
++++ b/drivers/media/platform/qcom/venus/Makefile
+@@ -3,7 +3,8 @@
+
+ venus-core-objs += core.o helpers.o firmware.o \
+ hfi_venus.o hfi_msgs.o hfi_cmds.o hfi.o \
+- hfi_parser.o pm_helpers.o dbgfs.o
++ hfi_parser.o pm_helpers.o dbgfs.o \
++ hfi_platform.o hfi_platform_v4.o \
+
+ venus-dec-objs += vdec.o vdec_ctrls.o
+ venus-enc-objs += venc.o venc_ctrls.o
+diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
+index 1859dd3f7f546..987b1d010c047 100644
+--- a/drivers/media/platform/qcom/venus/core.c
++++ b/drivers/media/platform/qcom/venus/core.c
+@@ -529,17 +529,6 @@ static const struct freq_tbl sdm845_freq_table[] = {
+ { 244800, 100000000 }, /* 1920x1080@30 */
+ };
+
+-static const struct codec_freq_data sdm845_codec_freq_data[] = {
+- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 },
+- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 },
+- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 },
+- { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10 },
+- { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10 },
+- { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10 },
+- { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10 },
+- { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10 },
+-};
+-
+ static const struct bw_tbl sdm845_bw_table_enc[] = {
+ { 1944000, 1612000, 0, 2416000, 0 }, /* 3840x2160@60 */
+ { 972000, 951000, 0, 1434000, 0 }, /* 3840x2160@30 */
+@@ -561,8 +550,6 @@ static const struct venus_resources sdm845_res = {
+ .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc),
+ .bw_tbl_dec = sdm845_bw_table_dec,
+ .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec),
+- .codec_freq_data = sdm845_codec_freq_data,
+- .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data),
+ .clks = {"core", "iface", "bus" },
+ .clks_num = 3,
+ .vcodec0_clks = { "core", "bus" },
+@@ -584,8 +571,6 @@ static const struct venus_resources sdm845_res_v2 = {
+ .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc),
+ .bw_tbl_dec = sdm845_bw_table_dec,
+ .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec),
+- .codec_freq_data = sdm845_codec_freq_data,
+- .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data),
+ .clks = {"core", "iface", "bus" },
+ .clks_num = 3,
+ .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
+@@ -635,8 +620,6 @@ static const struct venus_resources sc7180_res = {
+ .bw_tbl_enc_size = ARRAY_SIZE(sc7180_bw_table_enc),
+ .bw_tbl_dec = sc7180_bw_table_dec,
+ .bw_tbl_dec_size = ARRAY_SIZE(sc7180_bw_table_dec),
+- .codec_freq_data = sdm845_codec_freq_data,
+- .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data),
+ .clks = {"core", "iface", "bus" },
+ .clks_num = 3,
+ .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" },
+diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
+index e56d7b8142152..53d3202460ae9 100644
+--- a/drivers/media/platform/qcom/venus/core.h
++++ b/drivers/media/platform/qcom/venus/core.h
+@@ -36,13 +36,6 @@ struct reg_val {
+ u32 value;
+ };
+
+-struct codec_freq_data {
+- u32 pixfmt;
+- u32 session_type;
+- unsigned long vpp_freq;
+- unsigned long vsp_freq;
+-};
+-
+ struct bw_tbl {
+ u32 mbs_per_sec;
+ u32 avg;
+@@ -61,8 +54,6 @@ struct venus_resources {
+ unsigned int bw_tbl_dec_size;
+ const struct reg_val *reg_tbl;
+ unsigned int reg_tbl_size;
+- const struct codec_freq_data *codec_freq_data;
+- unsigned int codec_freq_data_size;
+ const char * const clks[VIDC_CLKS_NUM_MAX];
+ unsigned int clks_num;
+ const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
+@@ -280,7 +271,8 @@ struct venus_buffer {
+ struct clock_data {
+ u32 core_id;
+ unsigned long freq;
+- const struct codec_freq_data *codec_freq_data;
++ unsigned long vpp_freq;
++ unsigned long vsp_freq;
+ };
+
+ #define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb)
+diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
+index 5fdce5f07364e..9ad8abdc4d4f2 100644
+--- a/drivers/media/platform/qcom/venus/helpers.c
++++ b/drivers/media/platform/qcom/venus/helpers.c
+@@ -15,6 +15,7 @@
+ #include "helpers.h"
+ #include "hfi_helper.h"
+ #include "pm_helpers.h"
++#include "hfi_platform.h"
+
+ struct intbuf {
+ struct list_head list;
+@@ -1040,36 +1041,6 @@ int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode)
+ }
+ EXPORT_SYMBOL_GPL(venus_helper_set_work_mode);
+
+-int venus_helper_init_codec_freq_data(struct venus_inst *inst)
+-{
+- const struct codec_freq_data *data;
+- unsigned int i, data_size;
+- u32 pixfmt;
+- int ret = 0;
+-
+- if (!IS_V4(inst->core))
+- return 0;
+-
+- data = inst->core->res->codec_freq_data;
+- data_size = inst->core->res->codec_freq_data_size;
+- pixfmt = inst->session_type == VIDC_SESSION_TYPE_DEC ?
+- inst->fmt_out->pixfmt : inst->fmt_cap->pixfmt;
+-
+- for (i = 0; i < data_size; i++) {
+- if (data[i].pixfmt == pixfmt &&
+- data[i].session_type == inst->session_type) {
+- inst->clk_data.codec_freq_data = &data[i];
+- break;
+- }
+- }
+-
+- if (!inst->clk_data.codec_freq_data)
+- ret = -EINVAL;
+-
+- return ret;
+-}
+-EXPORT_SYMBOL_GPL(venus_helper_init_codec_freq_data);
+-
+ int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
+ unsigned int output_bufs,
+ unsigned int output2_bufs)
+@@ -1535,6 +1506,29 @@ void venus_helper_m2m_job_abort(void *priv)
+ }
+ EXPORT_SYMBOL_GPL(venus_helper_m2m_job_abort);
+
++int venus_helper_session_init(struct venus_inst *inst)
++{
++ enum hfi_version version = inst->core->res->hfi_version;
++ u32 session_type = inst->session_type;
++ u32 codec;
++ int ret;
++
++ codec = inst->session_type == VIDC_SESSION_TYPE_DEC ?
++ inst->fmt_out->pixfmt : inst->fmt_cap->pixfmt;
++
++ ret = hfi_session_init(inst, codec);
++ if (ret)
++ return ret;
++
++ inst->clk_data.vpp_freq = hfi_platform_get_codec_vpp_freq(version, codec,
++ session_type);
++ inst->clk_data.vsp_freq = hfi_platform_get_codec_vsp_freq(version, codec,
++ session_type);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(venus_helper_session_init);
++
+ void venus_helper_init_instance(struct venus_inst *inst)
+ {
+ if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
+diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h
+index a4a0562bc83f5..5407979bf234b 100644
+--- a/drivers/media/platform/qcom/venus/helpers.h
++++ b/drivers/media/platform/qcom/venus/helpers.h
+@@ -33,7 +33,6 @@ int venus_helper_set_output_resolution(struct venus_inst *inst,
+ unsigned int width, unsigned int height,
+ u32 buftype);
+ int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode);
+-int venus_helper_init_codec_freq_data(struct venus_inst *inst);
+ int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
+ unsigned int output_bufs,
+ unsigned int output2_bufs);
+@@ -48,6 +47,7 @@ unsigned int venus_helper_get_opb_size(struct venus_inst *inst);
+ void venus_helper_acquire_buf_ref(struct vb2_v4l2_buffer *vbuf);
+ void venus_helper_release_buf_ref(struct venus_inst *inst, unsigned int idx);
+ void venus_helper_init_instance(struct venus_inst *inst);
++int venus_helper_session_init(struct venus_inst *inst);
+ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 fmt, u32 *out_fmt,
+ u32 *out2_fmt, bool ubwc);
+ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst);
+diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c
+new file mode 100644
+index 0000000000000..65559cae21aaa
+--- /dev/null
++++ b/drivers/media/platform/qcom/venus/hfi_platform.c
+@@ -0,0 +1,49 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
++ */
++#include "hfi_platform.h"
++
++const struct hfi_platform *hfi_platform_get(enum hfi_version version)
++{
++ switch (version) {
++ case HFI_VERSION_4XX:
++ return &hfi_plat_v4;
++ default:
++ break;
++ }
++
++ return NULL;
++}
++
++unsigned long
++hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 codec, u32 session_type)
++{
++ const struct hfi_platform *plat;
++ unsigned long freq = 0;
++
++ plat = hfi_platform_get(version);
++ if (!plat)
++ return 0;
++
++ if (plat->codec_vpp_freq)
++ freq = plat->codec_vpp_freq(session_type, codec);
++
++ return freq;
++}
++
++unsigned long
++hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec, u32 session_type)
++{
++ const struct hfi_platform *plat;
++ unsigned long freq = 0;
++
++ plat = hfi_platform_get(version);
++ if (!plat)
++ return 0;
++
++ if (plat->codec_vpp_freq)
++ freq = plat->codec_vsp_freq(session_type, codec);
++
++ return freq;
++}
+diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h
+new file mode 100644
+index 0000000000000..8b07ecbb4c825
+--- /dev/null
++++ b/drivers/media/platform/qcom/venus/hfi_platform.h
+@@ -0,0 +1,34 @@
++/* SPDX-License-Identifier: GPL-2.0-only */
++/*
++ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
++ */
++
++#ifndef __HFI_PLATFORM_H__
++#define __HFI_PLATFORM_H__
++
++#include <linux/types.h>
++#include <linux/videodev2.h>
++
++#include "hfi.h"
++#include "hfi_helper.h"
++
++struct hfi_platform_codec_freq_data {
++ u32 pixfmt;
++ u32 session_type;
++ unsigned long vpp_freq;
++ unsigned long vsp_freq;
++};
++
++struct hfi_platform {
++ unsigned long (*codec_vpp_freq)(u32 session_type, u32 codec);
++ unsigned long (*codec_vsp_freq)(u32 session_type, u32 codec);
++};
++
++extern const struct hfi_platform hfi_plat_v4;
++
++const struct hfi_platform *hfi_platform_get(enum hfi_version version);
++unsigned long hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 codec,
++ u32 session_type);
++unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec,
++ u32 session_type);
++#endif
+diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v4.c b/drivers/media/platform/qcom/venus/hfi_platform_v4.c
+new file mode 100644
+index 0000000000000..4fc2fd04ca9d1
+--- /dev/null
++++ b/drivers/media/platform/qcom/venus/hfi_platform_v4.c
+@@ -0,0 +1,60 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
++ */
++#include "hfi_platform.h"
++
++static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
++ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 },
++ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 },
++ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 },
++ { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10 },
++ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10 },
++ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10 },
++ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10 },
++ { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10 },
++};
++
++static const struct hfi_platform_codec_freq_data *
++get_codec_freq_data(u32 session_type, u32 pixfmt)
++{
++ const struct hfi_platform_codec_freq_data *data = codec_freq_data;
++ unsigned int i, data_size = ARRAY_SIZE(codec_freq_data);
++ const struct hfi_platform_codec_freq_data *found = NULL;
++
++ for (i = 0; i < data_size; i++) {
++ if (data[i].pixfmt == pixfmt && data[i].session_type == session_type) {
++ found = &data[i];
++ break;
++ }
++ }
++
++ return found;
++}
++
++static unsigned long codec_vpp_freq(u32 session_type, u32 codec)
++{
++ const struct hfi_platform_codec_freq_data *data;
++
++ data = get_codec_freq_data(session_type, codec);
++ if (data)
++ return data->vpp_freq;
++
++ return 0;
++}
++
++static unsigned long codec_vsp_freq(u32 session_type, u32 codec)
++{
++ const struct hfi_platform_codec_freq_data *data;
++
++ data = get_codec_freq_data(session_type, codec);
++ if (data)
++ return data->vsp_freq;
++
++ return 0;
++}
++
++const struct hfi_platform hfi_plat_v4 = {
++ .codec_vpp_freq = codec_vpp_freq,
++ .codec_vsp_freq = codec_vsp_freq,
++};
+diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
+index 12c5811fefdf9..7c3541c35ab69 100644
+--- a/drivers/media/platform/qcom/venus/pm_helpers.c
++++ b/drivers/media/platform/qcom/venus/pm_helpers.c
+@@ -18,6 +18,7 @@
+ #include "hfi_parser.h"
+ #include "hfi_venus_io.h"
+ #include "pm_helpers.h"
++#include "hfi_platform.h"
+
+ static bool legacy_binding;
+
+@@ -506,7 +507,7 @@ min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load)
+ if (inst_pos->state != INST_START)
+ continue;
+
+- vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq;
++ vpp_freq = inst_pos->clk_data.vpp_freq;
+ coreid = inst_pos->clk_data.core_id;
+
+ mbs_per_sec = load_per_instance(inst_pos);
+@@ -555,7 +556,7 @@ static int decide_core(struct venus_inst *inst)
+ return 0;
+
+ inst_load = load_per_instance(inst);
+- inst_load *= inst->clk_data.codec_freq_data->vpp_freq;
++ inst_load *= inst->clk_data.vpp_freq;
+ max_freq = core->res->freq_tbl[0].freq;
+
+ min_loaded_core(inst, &min_coreid, &min_load);
+@@ -940,10 +941,10 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
+ if (inst->state != INST_START)
+ return 0;
+
+- vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
++ vpp_freq = mbs_per_sec * inst->clk_data.vpp_freq;
+ /* 21 / 20 is overhead factor */
+ vpp_freq += vpp_freq / 20;
+- vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq;
++ vsp_freq = mbs_per_sec * inst->clk_data.vsp_freq;
+
+ /* 10 / 7 is overhead factor */
+ if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
+index 6e9b62645e917..68390143d37df 100644
+--- a/drivers/media/platform/qcom/venus/vdec.c
++++ b/drivers/media/platform/qcom/venus/vdec.c
+@@ -767,7 +767,7 @@ static int vdec_session_init(struct venus_inst *inst)
+ {
+ int ret;
+
+- ret = hfi_session_init(inst, inst->fmt_out->pixfmt);
++ ret = venus_helper_session_init(inst);
+ if (ret == -EALREADY)
+ return 0;
+ else if (ret)
+@@ -778,10 +778,6 @@ static int vdec_session_init(struct venus_inst *inst)
+ if (ret)
+ goto deinit;
+
+- ret = venus_helper_init_codec_freq_data(inst);
+- if (ret)
+- goto deinit;
+-
+ return 0;
+ deinit:
+ hfi_session_deinit(inst);
+diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
+index 9f1b02e31b98c..bc62cb02458c9 100644
+--- a/drivers/media/platform/qcom/venus/venc.c
++++ b/drivers/media/platform/qcom/venus/venc.c
+@@ -726,7 +726,7 @@ static int venc_init_session(struct venus_inst *inst)
+ {
+ int ret;
+
+- ret = hfi_session_init(inst, inst->fmt_cap->pixfmt);
++ ret = venus_helper_session_init(inst);
+ if (ret == -EALREADY)
+ return 0;
+ else if (ret)
+@@ -747,10 +747,6 @@ static int venc_init_session(struct venus_inst *inst)
+ if (ret)
+ goto deinit;
+
+- ret = venus_helper_init_codec_freq_data(inst);
+- if (ret)
+- goto deinit;
+-
+ ret = venc_set_properties(inst);
+ if (ret)
+ goto deinit;
+--
+2.39.5
+
--- /dev/null
+From b72aa94cdf7b6f5002476e6cb28fb452466fd926 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Aug 2020 14:39:13 +0200
+Subject: media: venus: Get codecs and capabilities from hfi platform
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit e29929266be1ac0e40121f56b5c13b52c281db06 ]
+
+Wire up hfi platform codec and capabilities instead of
+getting them from firmware.
+
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../media/platform/qcom/venus/hfi_parser.c | 38 +++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c
+index be9a58ef04d86..7a2915befdb83 100644
+--- a/drivers/media/platform/qcom/venus/hfi_parser.c
++++ b/drivers/media/platform/qcom/venus/hfi_parser.c
+@@ -245,11 +245,49 @@ static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)
+ }
+ }
+
++static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
++{
++ const struct hfi_platform *plat;
++ const struct hfi_plat_caps *caps = NULL;
++ u32 enc_codecs, dec_codecs, count;
++ unsigned int entries;
++
++ if (inst)
++ return 0;
++
++ plat = hfi_platform_get(core->res->hfi_version);
++ if (!plat)
++ return -EINVAL;
++
++ if (plat->codecs)
++ plat->codecs(&enc_codecs, &dec_codecs, &count);
++
++ if (plat->capabilities)
++ caps = plat->capabilities(&entries);
++
++ if (!caps || !entries || !count)
++ return -EINVAL;
++
++ core->enc_codecs = enc_codecs;
++ core->dec_codecs = dec_codecs;
++ core->codecs_count = count;
++ core->max_sessions_supported = MAX_SESSIONS;
++ memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);
++ memcpy(core->caps, caps, sizeof(*caps) * entries);
++
++ return 0;
++}
++
+ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
+ u32 size)
+ {
+ unsigned int words_count = size >> 2;
+ u32 *word = buf, *data, codecs = 0, domain = 0;
++ int ret;
++
++ ret = hfi_platform_parser(core, inst);
++ if (!ret)
++ return HFI_ERR_NONE;
+
+ if (size % 4)
+ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
+--
+2.39.5
+
--- /dev/null
+From 9ed7bb77a925d0cf613d008ab9a8c0dbde56dc67 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Dec 2020 11:01:39 +0100
+Subject: media: venus: hfi: Correct session init return error
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit e922a33e0228fa314ffc4f70b3b9ffbc4aad1bbe ]
+
+The hfi_session_init can be called many times and it returns
+EINVAL when the session was already initialized. This error code
+(EINVAL) is confusing for the callers. Change hfi_session_init to
+return EALREADY error code when the session has been already
+initialized.
+
+Tested-by: Fritz Koenig <frkoenig@chromium.org>
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/venus/hfi.c | 2 +-
+ drivers/media/platform/qcom/venus/vdec.c | 2 +-
+ drivers/media/platform/qcom/venus/venc.c | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c
+index 17da555905e98..5fd53227c2c0b 100644
+--- a/drivers/media/platform/qcom/venus/hfi.c
++++ b/drivers/media/platform/qcom/venus/hfi.c
+@@ -212,7 +212,7 @@ int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
+ int ret;
+
+ if (inst->state != INST_UNINIT)
+- return -EINVAL;
++ return -EALREADY;
+
+ inst->hfi_codec = to_codec_type(pixfmt);
+ reinit_completion(&inst->done);
+diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
+index d91030a134c0e..6e9b62645e917 100644
+--- a/drivers/media/platform/qcom/venus/vdec.c
++++ b/drivers/media/platform/qcom/venus/vdec.c
+@@ -768,7 +768,7 @@ static int vdec_session_init(struct venus_inst *inst)
+ int ret;
+
+ ret = hfi_session_init(inst, inst->fmt_out->pixfmt);
+- if (ret == -EINVAL)
++ if (ret == -EALREADY)
+ return 0;
+ else if (ret)
+ return ret;
+diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
+index 18d20b4ca2cfd..9f1b02e31b98c 100644
+--- a/drivers/media/platform/qcom/venus/venc.c
++++ b/drivers/media/platform/qcom/venus/venc.c
+@@ -727,7 +727,7 @@ static int venc_init_session(struct venus_inst *inst)
+ int ret;
+
+ ret = hfi_session_init(inst, inst->fmt_cap->pixfmt);
+- if (ret == -EINVAL)
++ if (ret == -EALREADY)
+ return 0;
+ else if (ret)
+ return ret;
+--
+2.39.5
+
--- /dev/null
+From c3e8b918fb5a42bb217d552a8e3bbcbf9bdda9e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 22:50:09 +0530
+Subject: media: venus: hfi_parser: refactor hfi packet parsing logic
+
+From: Vikash Garodia <quic_vgarodia@quicinc.com>
+
+[ Upstream commit 9edaaa8e3e15aab1ca413ab50556de1975bcb329 ]
+
+words_count denotes the number of words in total payload, while data
+points to payload of various property within it. When words_count
+reaches last word, data can access memory beyond the total payload. This
+can lead to OOB access. With this patch, the utility api for handling
+individual properties now returns the size of data consumed. Accordingly
+remaining bytes are calculated before parsing the payload, thereby
+eliminates the OOB access possibilities.
+
+Cc: stable@vger.kernel.org
+Fixes: 1a73374a04e5 ("media: venus: hfi_parser: add common capability parser")
+Signed-off-by: Vikash Garodia <quic_vgarodia@quicinc.com>
+Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../media/platform/qcom/venus/hfi_parser.c | 98 ++++++++++++++-----
+ 1 file changed, 72 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c
+index 7a2915befdb83..c6be1564c876d 100644
+--- a/drivers/media/platform/qcom/venus/hfi_parser.c
++++ b/drivers/media/platform/qcom/venus/hfi_parser.c
+@@ -64,7 +64,7 @@ fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num)
+ cap->cap_bufs_mode_dynamic = true;
+ }
+
+-static void
++static int
+ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ {
+ struct hfi_buffer_alloc_mode_supported *mode = data;
+@@ -72,7 +72,7 @@ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ u32 *type;
+
+ if (num_entries > MAX_ALLOC_MODE_ENTRIES)
+- return;
++ return -EINVAL;
+
+ type = mode->data;
+
+@@ -84,6 +84,8 @@ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
+
+ type++;
+ }
++
++ return sizeof(*mode);
+ }
+
+ static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
+@@ -98,7 +100,7 @@ static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
+ cap->num_pl += num;
+ }
+
+-static void
++static int
+ parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ {
+ struct hfi_profile_level_supported *pl = data;
+@@ -106,12 +108,14 @@ parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {};
+
+ if (pl->profile_count > HFI_MAX_PROFILE_COUNT)
+- return;
++ return -EINVAL;
+
+ memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel));
+
+ for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
+ fill_profile_level, pl_arr, pl->profile_count);
++
++ return pl->profile_count * sizeof(*proflevel) + sizeof(u32);
+ }
+
+ static void
+@@ -126,7 +130,7 @@ fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num)
+ cap->num_caps += num;
+ }
+
+-static void
++static int
+ parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ {
+ struct hfi_capabilities *caps = data;
+@@ -135,12 +139,14 @@ parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {};
+
+ if (num_caps > MAX_CAP_ENTRIES)
+- return;
++ return -EINVAL;
+
+ memcpy(caps_arr, cap, num_caps * sizeof(*cap));
+
+ for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
+ fill_caps, caps_arr, num_caps);
++
++ return sizeof(*caps);
+ }
+
+ static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
+@@ -155,7 +161,7 @@ static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
+ cap->num_fmts += num_fmts;
+ }
+
+-static void
++static int
+ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ {
+ struct hfi_uncompressed_format_supported *fmt = data;
+@@ -164,7 +170,8 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {};
+ u32 entries = fmt->format_entries;
+ unsigned int i = 0;
+- u32 num_planes;
++ u32 num_planes = 0;
++ u32 size;
+
+ while (entries) {
+ num_planes = pinfo->num_planes;
+@@ -174,7 +181,7 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ i++;
+
+ if (i >= MAX_FMT_ENTRIES)
+- return;
++ return -EINVAL;
+
+ if (pinfo->num_planes > MAX_PLANES)
+ break;
+@@ -186,9 +193,13 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
+
+ for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
+ fill_raw_fmts, rawfmts, i);
++ size = fmt->format_entries * (sizeof(*constr) * num_planes + 2 * sizeof(u32))
++ + 2 * sizeof(u32);
++
++ return size;
+ }
+
+-static void parse_codecs(struct venus_core *core, void *data)
++static int parse_codecs(struct venus_core *core, void *data)
+ {
+ struct hfi_codec_supported *codecs = data;
+
+@@ -200,21 +211,27 @@ static void parse_codecs(struct venus_core *core, void *data)
+ core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK;
+ core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC;
+ }
++
++ return sizeof(*codecs);
+ }
+
+-static void parse_max_sessions(struct venus_core *core, const void *data)
++static int parse_max_sessions(struct venus_core *core, const void *data)
+ {
+ const struct hfi_max_sessions_supported *sessions = data;
+
+ core->max_sessions_supported = sessions->max_sessions;
++
++ return sizeof(*sessions);
+ }
+
+-static void parse_codecs_mask(u32 *codecs, u32 *domain, void *data)
++static int parse_codecs_mask(u32 *codecs, u32 *domain, void *data)
+ {
+ struct hfi_codec_mask_supported *mask = data;
+
+ *codecs = mask->codecs;
+ *domain = mask->video_domains;
++
++ return sizeof(*mask);
+ }
+
+ static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)
+@@ -281,8 +298,9 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
+ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
+ u32 size)
+ {
+- unsigned int words_count = size >> 2;
+- u32 *word = buf, *data, codecs = 0, domain = 0;
++ u32 *words = buf, *payload, codecs = 0, domain = 0;
++ u32 *frame_size = buf + size;
++ u32 rem_bytes = size;
+ int ret;
+
+ ret = hfi_platform_parser(core, inst);
+@@ -299,38 +317,66 @@ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
+ memset(core->caps, 0, sizeof(core->caps));
+ }
+
+- while (words_count) {
+- data = word + 1;
++ while (words < frame_size) {
++ payload = words + 1;
+
+- switch (*word) {
++ switch (*words) {
+ case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
+- parse_codecs(core, data);
++ if (rem_bytes <= sizeof(struct hfi_codec_supported))
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ ret = parse_codecs(core, payload);
++ if (ret < 0)
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
+ init_codecs(core);
+ break;
+ case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:
+- parse_max_sessions(core, data);
++ if (rem_bytes <= sizeof(struct hfi_max_sessions_supported))
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ ret = parse_max_sessions(core, payload);
+ break;
+ case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
+- parse_codecs_mask(&codecs, &domain, data);
++ if (rem_bytes <= sizeof(struct hfi_codec_mask_supported))
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ ret = parse_codecs_mask(&codecs, &domain, payload);
+ break;
+ case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
+- parse_raw_formats(core, codecs, domain, data);
++ if (rem_bytes <= sizeof(struct hfi_uncompressed_format_supported))
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ ret = parse_raw_formats(core, codecs, domain, payload);
+ break;
+ case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
+- parse_caps(core, codecs, domain, data);
++ if (rem_bytes <= sizeof(struct hfi_capabilities))
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ ret = parse_caps(core, codecs, domain, payload);
+ break;
+ case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
+- parse_profile_level(core, codecs, domain, data);
++ if (rem_bytes <= sizeof(struct hfi_profile_level_supported))
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ ret = parse_profile_level(core, codecs, domain, payload);
+ break;
+ case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
+- parse_alloc_mode(core, codecs, domain, data);
++ if (rem_bytes <= sizeof(struct hfi_buffer_alloc_mode_supported))
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ ret = parse_alloc_mode(core, codecs, domain, payload);
+ break;
+ default:
++ ret = sizeof(u32);
+ break;
+ }
+
+- word++;
+- words_count--;
++ if (ret < 0)
++ return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
++
++ words += ret / sizeof(u32);
++ rem_bytes -= ret;
+ }
+
+ if (!core->max_sessions_supported)
+--
+2.39.5
+
--- /dev/null
+From 68a66cb6387a8f56b5f459c22b806055c0cb844d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Aug 2020 13:07:07 +0200
+Subject: media: venus: hfi_plat: Add codecs and capabilities ops
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit 9822291e031f6d7149ae4f3fc00bd9c33ac2a084 ]
+
+Add ops to get the supported by the platform codecs and capabilities.
+
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/venus/hfi_platform.h | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h
+index 6794232322557..50512d142662f 100644
+--- a/drivers/media/platform/qcom/venus/hfi_platform.h
++++ b/drivers/media/platform/qcom/venus/hfi_platform.h
+@@ -47,6 +47,8 @@ struct hfi_platform_codec_freq_data {
+ struct hfi_platform {
+ unsigned long (*codec_vpp_freq)(u32 session_type, u32 codec);
+ unsigned long (*codec_vsp_freq)(u32 session_type, u32 codec);
++ void (*codecs)(u32 *enc_codecs, u32 *dec_codecs, u32 *count);
++ const struct hfi_plat_caps *(*capabilities)(unsigned int *entries);
+ };
+
+ extern const struct hfi_platform hfi_plat_v4;
+--
+2.39.5
+
--- /dev/null
+From 5fa4bedb0fda21cc926aa9f51e594f44cf9870ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Dec 2020 11:01:37 +0100
+Subject: media: venus: Limit HFI sessions to the maximum supported
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit 20891170f339a8754312a877f3d17f0e5dadd599 ]
+
+Currently we rely on firmware to return error when we reach the maximum
+supported number of sessions. But this errors are happened at reqbuf
+time which is a bit later. The more reasonable way looks like is to
+return the error on driver open.
+
+To achieve that modify hfi_session_create to return error when we reach
+maximum count of sessions and thus refuse open.
+
+Tested-by: Fritz Koenig <frkoenig@chromium.org>
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/venus/core.h | 1 +
+ drivers/media/platform/qcom/venus/hfi.c | 16 +++++++++++++---
+ drivers/media/platform/qcom/venus/hfi_parser.c | 3 +++
+ 3 files changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
+index 75d0068033276..e56d7b8142152 100644
+--- a/drivers/media/platform/qcom/venus/core.h
++++ b/drivers/media/platform/qcom/venus/core.h
+@@ -96,6 +96,7 @@ struct venus_format {
+ #define MAX_CAP_ENTRIES 32
+ #define MAX_ALLOC_MODE_ENTRIES 16
+ #define MAX_CODEC_NUM 32
++#define MAX_SESSIONS 16
+
+ struct raw_formats {
+ u32 buftype;
+diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c
+index 966b4d9b57a97..17da555905e98 100644
+--- a/drivers/media/platform/qcom/venus/hfi.c
++++ b/drivers/media/platform/qcom/venus/hfi.c
+@@ -178,6 +178,8 @@ static int wait_session_msg(struct venus_inst *inst)
+ int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
+ {
+ struct venus_core *core = inst->core;
++ bool max;
++ int ret;
+
+ if (!ops)
+ return -EINVAL;
+@@ -187,11 +189,19 @@ int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
+ inst->ops = ops;
+
+ mutex_lock(&core->lock);
+- list_add_tail(&inst->list, &core->instances);
+- atomic_inc(&core->insts_count);
++
++ max = atomic_add_unless(&core->insts_count, 1,
++ core->max_sessions_supported);
++ if (!max) {
++ ret = -EAGAIN;
++ } else {
++ list_add_tail(&inst->list, &core->instances);
++ ret = 0;
++ }
++
+ mutex_unlock(&core->lock);
+
+- return 0;
++ return ret;
+ }
+ EXPORT_SYMBOL_GPL(hfi_session_create);
+
+diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c
+index 32d2a9ed44003..94981a5e8e9af 100644
+--- a/drivers/media/platform/qcom/venus/hfi_parser.c
++++ b/drivers/media/platform/qcom/venus/hfi_parser.c
+@@ -295,6 +295,9 @@ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
+ words_count--;
+ }
+
++ if (!core->max_sessions_supported)
++ core->max_sessions_supported = MAX_SESSIONS;
++
+ parser_fini(inst, codecs, domain);
+
+ return HFI_ERR_NONE;
+--
+2.39.5
+
--- /dev/null
+From 68e451c45fec58515c724f58edf6ed8379db22dc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Nov 2020 15:37:52 +0100
+Subject: media: venus: pm_helpers: Check instance state when calculate
+ instance frequency
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit d33a94412ed1081f30d904cab54faea7c7b839fc ]
+
+Skip calculating instance frequency if it is not in running state.
+
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/venus/pm_helpers.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
+index fd55352d743ee..12c5811fefdf9 100644
+--- a/drivers/media/platform/qcom/venus/pm_helpers.c
++++ b/drivers/media/platform/qcom/venus/pm_helpers.c
+@@ -937,6 +937,9 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst,
+
+ mbs_per_sec = load_per_instance(inst) / fps;
+
++ if (inst->state != INST_START)
++ return 0;
++
+ vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
+ /* 21 / 20 is overhead factor */
+ vpp_freq += vpp_freq / 20;
+--
+2.39.5
+
--- /dev/null
+From 6c806d43c85d131b4af7df4c82d644baa0cb6337 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Aug 2020 13:04:09 +0200
+Subject: media: venus: Rename venus_caps to hfi_plat_caps
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit 8f3b41dcfb9a0fa2d2ca0af51c3eebd670dc153b ]
+
+Now when we have hfi platform make venus capabilities an
+hfi platform capabilities.
+
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/venus/core.h | 30 ++-----------------
+ drivers/media/platform/qcom/venus/helpers.c | 6 ++--
+ .../media/platform/qcom/venus/hfi_parser.c | 18 +++++------
+ .../media/platform/qcom/venus/hfi_parser.h | 2 +-
+ .../media/platform/qcom/venus/hfi_platform.h | 25 ++++++++++++++++
+ 5 files changed, 41 insertions(+), 40 deletions(-)
+
+diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
+index 53d3202460ae9..785a5bbb19c3c 100644
+--- a/drivers/media/platform/qcom/venus/core.h
++++ b/drivers/media/platform/qcom/venus/core.h
+@@ -14,6 +14,7 @@
+
+ #include "dbgfs.h"
+ #include "hfi.h"
++#include "hfi_platform.h"
+
+ #define VDBGL "VenusLow : "
+ #define VDBGM "VenusMed : "
+@@ -82,31 +83,6 @@ struct venus_format {
+ u32 flags;
+ };
+
+-#define MAX_PLANES 4
+-#define MAX_FMT_ENTRIES 32
+-#define MAX_CAP_ENTRIES 32
+-#define MAX_ALLOC_MODE_ENTRIES 16
+-#define MAX_CODEC_NUM 32
+-#define MAX_SESSIONS 16
+-
+-struct raw_formats {
+- u32 buftype;
+- u32 fmt;
+-};
+-
+-struct venus_caps {
+- u32 codec;
+- u32 domain;
+- bool cap_bufs_mode_dynamic;
+- unsigned int num_caps;
+- struct hfi_capability caps[MAX_CAP_ENTRIES];
+- unsigned int num_pl;
+- struct hfi_profile_level pl[HFI_MAX_PROFILE_COUNT];
+- unsigned int num_fmts;
+- struct raw_formats fmts[MAX_FMT_ENTRIES];
+- bool valid; /* used only for Venus v1xx */
+-};
+-
+ /**
+ * struct venus_core - holds core parameters valid for all instances
+ *
+@@ -199,7 +175,7 @@ struct venus_core {
+ void *priv;
+ const struct hfi_ops *ops;
+ struct delayed_work work;
+- struct venus_caps caps[MAX_CODEC_NUM];
++ struct hfi_plat_caps caps[MAX_CODEC_NUM];
+ unsigned int codecs_count;
+ unsigned int core0_usage_count;
+ unsigned int core1_usage_count;
+@@ -434,7 +410,7 @@ static inline void *to_hfi_priv(struct venus_core *core)
+ return core->priv;
+ }
+
+-static inline struct venus_caps *
++static inline struct hfi_plat_caps *
+ venus_caps_by_codec(struct venus_core *core, u32 codec, u32 domain)
+ {
+ unsigned int c;
+diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
+index 9ad8abdc4d4f2..dcf9fc0da1ce4 100644
+--- a/drivers/media/platform/qcom/venus/helpers.c
++++ b/drivers/media/platform/qcom/venus/helpers.c
+@@ -481,7 +481,7 @@ session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
+ static bool is_dynamic_bufmode(struct venus_inst *inst)
+ {
+ struct venus_core *core = inst->core;
+- struct venus_caps *caps;
++ struct hfi_plat_caps *caps;
+
+ /*
+ * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports
+@@ -1539,7 +1539,7 @@ void venus_helper_init_instance(struct venus_inst *inst)
+ }
+ EXPORT_SYMBOL_GPL(venus_helper_init_instance);
+
+-static bool find_fmt_from_caps(struct venus_caps *caps, u32 buftype, u32 fmt)
++static bool find_fmt_from_caps(struct hfi_plat_caps *caps, u32 buftype, u32 fmt)
+ {
+ unsigned int i;
+
+@@ -1556,7 +1556,7 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt,
+ u32 *out_fmt, u32 *out2_fmt, bool ubwc)
+ {
+ struct venus_core *core = inst->core;
+- struct venus_caps *caps;
++ struct hfi_plat_caps *caps;
+ u32 ubwc_fmt, fmt = to_hfi_raw_fmt(v4l2_fmt);
+ bool found, found_ubwc;
+
+diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c
+index 94981a5e8e9af..be9a58ef04d86 100644
+--- a/drivers/media/platform/qcom/venus/hfi_parser.c
++++ b/drivers/media/platform/qcom/venus/hfi_parser.c
+@@ -11,12 +11,12 @@
+ #include "hfi_helper.h"
+ #include "hfi_parser.h"
+
+-typedef void (*func)(struct venus_caps *cap, const void *data,
++typedef void (*func)(struct hfi_plat_caps *cap, const void *data,
+ unsigned int size);
+
+ static void init_codecs(struct venus_core *core)
+ {
+- struct venus_caps *caps = core->caps, *cap;
++ struct hfi_plat_caps *caps = core->caps, *cap;
+ unsigned long bit;
+
+ core->codecs_count = 0;
+@@ -39,11 +39,11 @@ static void init_codecs(struct venus_core *core)
+ }
+ }
+
+-static void for_each_codec(struct venus_caps *caps, unsigned int caps_num,
++static void for_each_codec(struct hfi_plat_caps *caps, unsigned int caps_num,
+ u32 codecs, u32 domain, func cb, void *data,
+ unsigned int size)
+ {
+- struct venus_caps *cap;
++ struct hfi_plat_caps *cap;
+ unsigned int i;
+
+ for (i = 0; i < caps_num; i++) {
+@@ -56,7 +56,7 @@ static void for_each_codec(struct venus_caps *caps, unsigned int caps_num,
+ }
+
+ static void
+-fill_buf_mode(struct venus_caps *cap, const void *data, unsigned int num)
++fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num)
+ {
+ const u32 *type = data;
+
+@@ -86,7 +86,7 @@ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ }
+ }
+
+-static void fill_profile_level(struct venus_caps *cap, const void *data,
++static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
+ unsigned int num)
+ {
+ const struct hfi_profile_level *pl = data;
+@@ -115,7 +115,7 @@ parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ }
+
+ static void
+-fill_caps(struct venus_caps *cap, const void *data, unsigned int num)
++fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num)
+ {
+ const struct hfi_capability *caps = data;
+
+@@ -143,7 +143,7 @@ parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)
+ fill_caps, caps_arr, num_caps);
+ }
+
+-static void fill_raw_fmts(struct venus_caps *cap, const void *fmts,
++static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
+ unsigned int num_fmts)
+ {
+ const struct raw_formats *formats = fmts;
+@@ -228,7 +228,7 @@ static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)
+
+ static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)
+ {
+- struct venus_caps *caps, *cap;
++ struct hfi_plat_caps *caps, *cap;
+ unsigned int i;
+ u32 dom;
+
+diff --git a/drivers/media/platform/qcom/venus/hfi_parser.h b/drivers/media/platform/qcom/venus/hfi_parser.h
+index 264e6dd2415fe..7f59d82110f9c 100644
+--- a/drivers/media/platform/qcom/venus/hfi_parser.h
++++ b/drivers/media/platform/qcom/venus/hfi_parser.h
+@@ -16,7 +16,7 @@ static inline u32 get_cap(struct venus_inst *inst, u32 type, u32 which)
+ {
+ struct venus_core *core = inst->core;
+ struct hfi_capability *cap = NULL;
+- struct venus_caps *caps;
++ struct hfi_plat_caps *caps;
+ unsigned int i;
+
+ caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
+diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h
+index 8b07ecbb4c825..6794232322557 100644
+--- a/drivers/media/platform/qcom/venus/hfi_platform.h
++++ b/drivers/media/platform/qcom/venus/hfi_platform.h
+@@ -12,6 +12,31 @@
+ #include "hfi.h"
+ #include "hfi_helper.h"
+
++#define MAX_PLANES 4
++#define MAX_FMT_ENTRIES 32
++#define MAX_CAP_ENTRIES 32
++#define MAX_ALLOC_MODE_ENTRIES 16
++#define MAX_CODEC_NUM 32
++#define MAX_SESSIONS 16
++
++struct raw_formats {
++ u32 buftype;
++ u32 fmt;
++};
++
++struct hfi_plat_caps {
++ u32 codec;
++ u32 domain;
++ bool cap_bufs_mode_dynamic;
++ unsigned int num_caps;
++ struct hfi_capability caps[MAX_CAP_ENTRIES];
++ unsigned int num_pl;
++ struct hfi_profile_level pl[HFI_MAX_PROFILE_COUNT];
++ unsigned int num_fmts;
++ struct raw_formats fmts[MAX_FMT_ENTRIES];
++ bool valid; /* used only for Venus v1xx */
++};
++
+ struct hfi_platform_codec_freq_data {
+ u32 pixfmt;
+ u32 session_type;
+--
+2.39.5
+
--- /dev/null
+From 1c4c7eb8c7717549ac62b7ad29d72e6bf937997e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Dec 2020 11:01:36 +0100
+Subject: media: venus: venc: Init the session only once in queue_setup
+
+From: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+
+[ Upstream commit 5f2ca73dcca96c3de96a0e4d9ea24ebb46c55d2e ]
+
+Init the hfi session only once in queue_setup and also cover that
+with inst->lock.
+
+Tested-by: Fritz Koenig <frkoenig@chromium.org>
+Signed-off-by: Stanimir Varbanov <stanimir.varbanov@linaro.org>
+Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
+Stable-dep-of: 9edaaa8e3e15 ("media: venus: hfi_parser: refactor hfi packet parsing logic")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/media/platform/qcom/venus/venc.c | 85 ++++++++++++++++++------
+ 1 file changed, 64 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
+index e2d0fd5eaf29a..18d20b4ca2cfd 100644
+--- a/drivers/media/platform/qcom/venus/venc.c
++++ b/drivers/media/platform/qcom/venus/venc.c
+@@ -727,7 +727,9 @@ static int venc_init_session(struct venus_inst *inst)
+ int ret;
+
+ ret = hfi_session_init(inst, inst->fmt_cap->pixfmt);
+- if (ret)
++ if (ret == -EINVAL)
++ return 0;
++ else if (ret)
+ return ret;
+
+ ret = venus_helper_set_input_resolution(inst, inst->width,
+@@ -764,17 +766,13 @@ static int venc_out_num_buffers(struct venus_inst *inst, unsigned int *num)
+ struct hfi_buffer_requirements bufreq;
+ int ret;
+
+- ret = venc_init_session(inst);
++ ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
+ if (ret)
+ return ret;
+
+- ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
+-
+ *num = bufreq.count_actual;
+
+- hfi_session_deinit(inst);
+-
+- return ret;
++ return 0;
+ }
+
+ static int venc_queue_setup(struct vb2_queue *q,
+@@ -783,7 +781,7 @@ static int venc_queue_setup(struct vb2_queue *q,
+ {
+ struct venus_inst *inst = vb2_get_drv_priv(q);
+ unsigned int num, min = 4;
+- int ret = 0;
++ int ret;
+
+ if (*num_planes) {
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
+@@ -805,6 +803,13 @@ static int venc_queue_setup(struct vb2_queue *q,
+ return 0;
+ }
+
++ mutex_lock(&inst->lock);
++ ret = venc_init_session(inst);
++ mutex_unlock(&inst->lock);
++
++ if (ret)
++ return ret;
++
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ *num_planes = inst->fmt_out->num_planes;
+@@ -840,6 +845,49 @@ static int venc_queue_setup(struct vb2_queue *q,
+ return ret;
+ }
+
++static int venc_buf_init(struct vb2_buffer *vb)
++{
++ struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
++
++ inst->buf_count++;
++
++ return venus_helper_vb2_buf_init(vb);
++}
++
++static void venc_release_session(struct venus_inst *inst)
++{
++ int ret;
++
++ mutex_lock(&inst->lock);
++
++ ret = hfi_session_deinit(inst);
++ if (ret || inst->session_error)
++ hfi_session_abort(inst);
++
++ mutex_unlock(&inst->lock);
++
++ venus_pm_load_scale(inst);
++ INIT_LIST_HEAD(&inst->registeredbufs);
++ venus_pm_release_core(inst);
++}
++
++static void venc_buf_cleanup(struct vb2_buffer *vb)
++{
++ struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
++ struct venus_buffer *buf = to_venus_buffer(vbuf);
++
++ mutex_lock(&inst->lock);
++ if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
++ if (!list_empty(&inst->registeredbufs))
++ list_del_init(&buf->reg_list);
++ mutex_unlock(&inst->lock);
++
++ inst->buf_count--;
++ if (!inst->buf_count)
++ venc_release_session(inst);
++}
++
+ static int venc_verify_conf(struct venus_inst *inst)
+ {
+ enum hfi_version ver = inst->core->res->hfi_version;
+@@ -890,38 +938,32 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count)
+ inst->sequence_cap = 0;
+ inst->sequence_out = 0;
+
+- ret = venc_init_session(inst);
+- if (ret)
+- goto bufs_done;
+-
+ ret = venus_pm_acquire_core(inst);
+ if (ret)
+- goto deinit_sess;
++ goto error;
+
+ ret = venc_set_properties(inst);
+ if (ret)
+- goto deinit_sess;
++ goto error;
+
+ ret = venc_verify_conf(inst);
+ if (ret)
+- goto deinit_sess;
++ goto error;
+
+ ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
+ inst->num_output_bufs, 0);
+ if (ret)
+- goto deinit_sess;
++ goto error;
+
+ ret = venus_helper_vb2_start_streaming(inst);
+ if (ret)
+- goto deinit_sess;
++ goto error;
+
+ mutex_unlock(&inst->lock);
+
+ return 0;
+
+-deinit_sess:
+- hfi_session_deinit(inst);
+-bufs_done:
++error:
+ venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED);
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ inst->streamon_out = 0;
+@@ -933,7 +975,8 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count)
+
+ static const struct vb2_ops venc_vb2_ops = {
+ .queue_setup = venc_queue_setup,
+- .buf_init = venus_helper_vb2_buf_init,
++ .buf_init = venc_buf_init,
++ .buf_cleanup = venc_buf_cleanup,
+ .buf_prepare = venus_helper_vb2_buf_prepare,
+ .start_streaming = venc_start_streaming,
+ .stop_streaming = venus_helper_vb2_stop_streaming,
+--
+2.39.5
+
--- /dev/null
+From 2403bbf5473c0afbd398d66c28cda3f3a367dff4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Mar 2025 18:32:44 +0100
+Subject: net: dsa: mv88e6xxx: fix VTU methods for 6320 family
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Marek Behún <kabel@kernel.org>
+
+[ Upstream commit f9a457722cf5e3534be5ffab549d6b49737fca72 ]
+
+The VTU registers of the 6320 family use the 6352 semantics, not 6185.
+Fix it.
+
+Fixes: b8fee9571063 ("net: dsa: mv88e6xxx: add VLAN Get Next support")
+Signed-off-by: Marek Behún <kabel@kernel.org>
+Cc: <stable@vger.kernel.org> # 5.15.x
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Link: https://patch.msgid.link/20250317173250.28780-2-kabel@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/dsa/mv88e6xxx/chip.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
+index e590ea87b6ea2..ebc8580873940 100644
+--- a/drivers/net/dsa/mv88e6xxx/chip.c
++++ b/drivers/net/dsa/mv88e6xxx/chip.c
+@@ -4170,8 +4170,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
+ .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
+ .pot_clear = mv88e6xxx_g2_pot_clear,
+ .reset = mv88e6352_g1_reset,
+- .vtu_getnext = mv88e6185_g1_vtu_getnext,
+- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
++ .vtu_getnext = mv88e6352_g1_vtu_getnext,
++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .gpio_ops = &mv88e6352_gpio_ops,
+ .avb_ops = &mv88e6352_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
+@@ -4212,8 +4212,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
+ .watchdog_ops = &mv88e6390_watchdog_ops,
+ .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
+ .reset = mv88e6352_g1_reset,
+- .vtu_getnext = mv88e6185_g1_vtu_getnext,
+- .vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
++ .vtu_getnext = mv88e6352_g1_vtu_getnext,
++ .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .gpio_ops = &mv88e6352_gpio_ops,
+ .avb_ops = &mv88e6352_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
+--
+2.39.5
+
--- /dev/null
+From 986e2a9c8da3498840d7113f1984acb946e2a000 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Jul 2022 20:41:30 +0200
+Subject: PCI: Assign PCI domain IDs by ida_alloc()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pali Rohár <pali@kernel.org>
+
+[ Upstream commit c14f7ccc9f5dcf9d06ddeec706f85405b2c80600 ]
+
+Replace assignment of PCI domain IDs from atomic_inc_return() to
+ida_alloc().
+
+Use two IDAs, one for static domain allocations (those which are defined in
+device tree) and second for dynamic allocations (all other).
+
+During removal of root bus / host bridge, also release the domain ID. The
+released ID can be reused again, for example when dynamically loading and
+unloading native PCI host bridge drivers.
+
+This change also allows to mix static device tree assignment and dynamic by
+kernel as all static allocations are reserved in dynamic pool.
+
+[bhelgaas: set "err" if "bus->domain_nr < 0"]
+Link: https://lore.kernel.org/r/20220714184130.5436-1-pali@kernel.org
+Signed-off-by: Pali Rohár <pali@kernel.org>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: 804443c1f278 ("PCI: Fix reference leak in pci_register_host_bridge()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pci.c | 103 +++++++++++++++++++++++++------------------
+ drivers/pci/probe.c | 7 +++
+ drivers/pci/remove.c | 6 +++
+ include/linux/pci.h | 1 +
+ 4 files changed, 74 insertions(+), 43 deletions(-)
+
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index 1d4585b07de3b..24916e78c507c 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -6467,60 +6467,70 @@ static void pci_no_domains(void)
+ }
+
+ #ifdef CONFIG_PCI_DOMAINS_GENERIC
+-static atomic_t __domain_nr = ATOMIC_INIT(-1);
++static DEFINE_IDA(pci_domain_nr_static_ida);
++static DEFINE_IDA(pci_domain_nr_dynamic_ida);
+
+-static int pci_get_new_domain_nr(void)
++static void of_pci_reserve_static_domain_nr(void)
+ {
+- return atomic_inc_return(&__domain_nr);
++ struct device_node *np;
++ int domain_nr;
++
++ for_each_node_by_type(np, "pci") {
++ domain_nr = of_get_pci_domain_nr(np);
++ if (domain_nr < 0)
++ continue;
++ /*
++ * Permanently allocate domain_nr in dynamic_ida
++ * to prevent it from dynamic allocation.
++ */
++ ida_alloc_range(&pci_domain_nr_dynamic_ida,
++ domain_nr, domain_nr, GFP_KERNEL);
++ }
+ }
+
+ static int of_pci_bus_find_domain_nr(struct device *parent)
+ {
+- static int use_dt_domains = -1;
+- int domain = -1;
++ static bool static_domains_reserved = false;
++ int domain_nr;
+
+- if (parent)
+- domain = of_get_pci_domain_nr(parent->of_node);
++ /* On the first call scan device tree for static allocations. */
++ if (!static_domains_reserved) {
++ of_pci_reserve_static_domain_nr();
++ static_domains_reserved = true;
++ }
++
++ if (parent) {
++ /*
++ * If domain is in DT, allocate it in static IDA. This
++ * prevents duplicate static allocations in case of errors
++ * in DT.
++ */
++ domain_nr = of_get_pci_domain_nr(parent->of_node);
++ if (domain_nr >= 0)
++ return ida_alloc_range(&pci_domain_nr_static_ida,
++ domain_nr, domain_nr,
++ GFP_KERNEL);
++ }
+
+ /*
+- * Check DT domain and use_dt_domains values.
+- *
+- * If DT domain property is valid (domain >= 0) and
+- * use_dt_domains != 0, the DT assignment is valid since this means
+- * we have not previously allocated a domain number by using
+- * pci_get_new_domain_nr(); we should also update use_dt_domains to
+- * 1, to indicate that we have just assigned a domain number from
+- * DT.
+- *
+- * If DT domain property value is not valid (ie domain < 0), and we
+- * have not previously assigned a domain number from DT
+- * (use_dt_domains != 1) we should assign a domain number by
+- * using the:
+- *
+- * pci_get_new_domain_nr()
+- *
+- * API and update the use_dt_domains value to keep track of method we
+- * are using to assign domain numbers (use_dt_domains = 0).
+- *
+- * All other combinations imply we have a platform that is trying
+- * to mix domain numbers obtained from DT and pci_get_new_domain_nr(),
+- * which is a recipe for domain mishandling and it is prevented by
+- * invalidating the domain value (domain = -1) and printing a
+- * corresponding error.
++ * If domain was not specified in DT, choose a free ID from dynamic
++ * allocations. All domain numbers from DT are permanently in
++ * dynamic allocations to prevent assigning them to other DT nodes
++ * without static domain.
+ */
+- if (domain >= 0 && use_dt_domains) {
+- use_dt_domains = 1;
+- } else if (domain < 0 && use_dt_domains != 1) {
+- use_dt_domains = 0;
+- domain = pci_get_new_domain_nr();
+- } else {
+- if (parent)
+- pr_err("Node %pOF has ", parent->of_node);
+- pr_err("Inconsistent \"linux,pci-domain\" property in DT\n");
+- domain = -1;
+- }
++ return ida_alloc(&pci_domain_nr_dynamic_ida, GFP_KERNEL);
++}
+
+- return domain;
++static void of_pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent)
++{
++ if (bus->domain_nr < 0)
++ return;
++
++ /* Release domain from IDA where it was allocated. */
++ if (of_get_pci_domain_nr(parent->of_node) == bus->domain_nr)
++ ida_free(&pci_domain_nr_static_ida, bus->domain_nr);
++ else
++ ida_free(&pci_domain_nr_dynamic_ida, bus->domain_nr);
+ }
+
+ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+@@ -6528,6 +6538,13 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent)
+ return acpi_disabled ? of_pci_bus_find_domain_nr(parent) :
+ acpi_pci_bus_find_domain_nr(bus);
+ }
++
++void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent)
++{
++ if (!acpi_disabled)
++ return;
++ of_pci_bus_release_domain_nr(bus, parent);
++}
+ #endif
+
+ /**
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index a2c53f6d1848a..012ca242bedf4 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -904,6 +904,10 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ bus->domain_nr = pci_bus_find_domain_nr(bus, parent);
+ else
+ bus->domain_nr = bridge->domain_nr;
++ if (bus->domain_nr < 0) {
++ err = bus->domain_nr;
++ goto free;
++ }
+ #endif
+
+ b = pci_find_bus(pci_domain_nr(bus), bridge->busnr);
+@@ -1022,6 +1026,9 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ device_del(&bridge->dev);
+
+ free:
++#ifdef CONFIG_PCI_DOMAINS_GENERIC
++ pci_bus_release_domain_nr(bus, parent);
++#endif
+ kfree(bus);
+ return err;
+ }
+diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
+index 95dec03d9f2a9..611547b52b46d 100644
+--- a/drivers/pci/remove.c
++++ b/drivers/pci/remove.c
+@@ -159,6 +159,12 @@ void pci_remove_root_bus(struct pci_bus *bus)
+ pci_remove_bus(bus);
+ host_bridge->bus = NULL;
+
++#ifdef CONFIG_PCI_DOMAINS_GENERIC
++ /* Release domain_nr if it was dynamically allocated */
++ if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET)
++ pci_bus_release_domain_nr(bus, host_bridge->dev.parent);
++#endif
++
+ /* remove the host bridge */
+ device_del(&host_bridge->dev);
+ }
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index a0fd1fe4189e4..d3d84eb466f02 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -1667,6 +1667,7 @@ static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus)
+ { return 0; }
+ #endif
+ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent);
++void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent);
+ #endif
+
+ /* Some architectures require additional setup to direct VGA traffic */
+--
+2.39.5
+
--- /dev/null
+From 490e7fc8f363468103dd2ac020913a6bec7f2bdb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Jul 2021 20:50:07 +0800
+Subject: PCI: Coalesce host bridge contiguous apertures
+
+From: Kai-Heng Feng <kai.heng.feng@canonical.com>
+
+[ Upstream commit 65db04053efea3f3e412a7e0cc599962999c96b4 ]
+
+Built-in graphics on HP EliteDesk 805 G6 doesn't work because graphics
+can't get the BAR it needs:
+
+ pci_bus 0000:00: root bus resource [mem 0x10020200000-0x100303fffff window]
+ pci_bus 0000:00: root bus resource [mem 0x10030400000-0x100401fffff window]
+
+ pci 0000:00:08.1: bridge window [mem 0xd2000000-0xd23fffff]
+ pci 0000:00:08.1: bridge window [mem 0x10030000000-0x100401fffff 64bit pref]
+ pci 0000:00:08.1: can't claim BAR 15 [mem 0x10030000000-0x100401fffff 64bit pref]: no compatible bridge window
+ pci 0000:00:08.1: [mem 0x10030000000-0x100401fffff 64bit pref] clipped to [mem 0x10030000000-0x100303fffff 64bit pref]
+ pci 0000:00:08.1: bridge window [mem 0x10030000000-0x100303fffff 64bit pref]
+ pci 0000:07:00.0: can't claim BAR 0 [mem 0x10030000000-0x1003fffffff 64bit pref]: no compatible bridge window
+ pci 0000:07:00.0: can't claim BAR 2 [mem 0x10040000000-0x100401fffff 64bit pref]: no compatible bridge window
+
+However, the root bus has two contiguous apertures that can contain the
+child resource requested.
+
+Coalesce contiguous apertures so we can allocate from the entire contiguous
+region.
+
+[bhelgaas: fold in https://lore.kernel.org/r/20210528170242.1564038-1-kai.heng.feng@canonical.com]
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=212013
+Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
+Link: https://lore.kernel.org/r/20210401131252.531935-1-kai.heng.feng@canonical.com
+Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: 804443c1f278 ("PCI: Fix reference leak in pci_register_host_bridge()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/probe.c | 31 +++++++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index be7973e249cd7..a2c53f6d1848a 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -878,11 +878,11 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus)
+ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ {
+ struct device *parent = bridge->dev.parent;
+- struct resource_entry *window, *n;
++ struct resource_entry *window, *next, *n;
+ struct pci_bus *bus, *b;
+- resource_size_t offset;
++ resource_size_t offset, next_offset;
+ LIST_HEAD(resources);
+- struct resource *res;
++ struct resource *res, *next_res;
+ char addr[64], *fmt;
+ const char *name;
+ int err;
+@@ -962,11 +962,34 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ if (nr_node_ids > 1 && pcibus_to_node(bus) == NUMA_NO_NODE)
+ dev_warn(&bus->dev, "Unknown NUMA node; performance will be reduced\n");
+
++ /* Coalesce contiguous windows */
++ resource_list_for_each_entry_safe(window, n, &resources) {
++ if (list_is_last(&window->node, &resources))
++ break;
++
++ next = list_next_entry(window, node);
++ offset = window->offset;
++ res = window->res;
++ next_offset = next->offset;
++ next_res = next->res;
++
++ if (res->flags != next_res->flags || offset != next_offset)
++ continue;
++
++ if (res->end + 1 == next_res->start) {
++ next_res->start = res->start;
++ res->flags = res->start = res->end = 0;
++ }
++ }
++
+ /* Add initial resources to the bus */
+ resource_list_for_each_entry_safe(window, n, &resources) {
+- list_move_tail(&window->node, &bridge->windows);
+ offset = window->offset;
+ res = window->res;
++ if (!res->end)
++ continue;
++
++ list_move_tail(&window->node, &bridge->windows);
+
+ if (res->flags & IORESOURCE_BUS)
+ pci_bus_insert_busn_res(bus, bus->number, res->end);
+--
+2.39.5
+
--- /dev/null
+From 3679a05ddfeba7a765cdca0ffbb597b086ebeaf8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 10:14:40 +0800
+Subject: PCI: Fix reference leak in pci_register_host_bridge()
+
+From: Ma Ke <make24@iscas.ac.cn>
+
+[ Upstream commit 804443c1f27883926de94c849d91f5b7d7d696e9 ]
+
+If device_register() fails, call put_device() to give up the reference to
+avoid a memory leak, per the comment at device_register().
+
+Found by code review.
+
+Link: https://lore.kernel.org/r/20250225021440.3130264-1-make24@iscas.ac.cn
+Fixes: 37d6a0a6f470 ("PCI: Add pci_register_host_bridge() interface")
+Signed-off-by: Ma Ke <make24@iscas.ac.cn>
+[bhelgaas: squash Dan Carpenter's double free fix from
+https://lore.kernel.org/r/db806a6c-a91b-4e5a-a84b-6b7e01bdac85@stanley.mountain]
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/probe.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index 012ca242bedf4..7f3d10957eca7 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -883,6 +883,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ resource_size_t offset, next_offset;
+ LIST_HEAD(resources);
+ struct resource *res, *next_res;
++ bool bus_registered = false;
+ char addr[64], *fmt;
+ const char *name;
+ int err;
+@@ -944,6 +945,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ name = dev_name(&bus->dev);
+
+ err = device_register(&bus->dev);
++ bus_registered = true;
+ if (err)
+ goto unregister;
+
+@@ -1024,12 +1026,15 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ unregister:
+ put_device(&bridge->dev);
+ device_del(&bridge->dev);
+-
+ free:
+ #ifdef CONFIG_PCI_DOMAINS_GENERIC
+ pci_bus_release_domain_nr(bus, parent);
+ #endif
+- kfree(bus);
++ if (bus_registered)
++ put_device(&bus->dev);
++ else
++ kfree(bus);
++
+ return err;
+ }
+
+--
+2.39.5
+
--- /dev/null
+From ac5ff084ef8a10127a512e26532d6078d903aaf9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 Jul 2021 02:06:50 +0800
+Subject: PCI: Introduce domain_nr in pci_host_bridge
+
+From: Boqun Feng <boqun.feng@gmail.com>
+
+[ Upstream commit 15d82ca23c996d50062286d27ed6a42a8105c04a ]
+
+Currently we retrieve the PCI domain number of the host bridge from the
+bus sysdata (or pci_config_window if PCI_DOMAINS_GENERIC=y). Actually
+we have the information at PCI host bridge probing time, and it makes
+sense that we store it into pci_host_bridge. One benefit of doing so is
+the requirement for supporting PCI on Hyper-V for ARM64, because the
+host bridge of Hyper-V doesn't have pci_config_window, whereas ARM64 is
+a PCI_DOMAINS_GENERIC=y arch, so we cannot retrieve the PCI domain
+number from pci_config_window on ARM64 Hyper-V guest.
+
+As the preparation for ARM64 Hyper-V PCI support, we introduce the
+domain_nr in pci_host_bridge and a sentinel value to allow drivers to
+set domain numbers properly at probing time. Currently
+CONFIG_PCI_DOMAINS_GENERIC=y archs are only users of this
+newly-introduced field.
+
+Link: https://lore.kernel.org/r/20210726180657.142727-2-boqun.feng@gmail.com
+Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: 804443c1f278 ("PCI: Fix reference leak in pci_register_host_bridge()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/probe.c | 6 +++++-
+ include/linux/pci.h | 11 +++++++++++
+ 2 files changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
+index 6439fc2e526c7..be7973e249cd7 100644
+--- a/drivers/pci/probe.c
++++ b/drivers/pci/probe.c
+@@ -595,6 +595,7 @@ static void pci_init_host_bridge(struct pci_host_bridge *bridge)
+ bridge->native_pme = 1;
+ bridge->native_ltr = 1;
+ bridge->native_dpc = 1;
++ bridge->domain_nr = PCI_DOMAIN_NR_NOT_SET;
+
+ device_initialize(&bridge->dev);
+ }
+@@ -899,7 +900,10 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
+ bus->ops = bridge->ops;
+ bus->number = bus->busn_res.start = bridge->busnr;
+ #ifdef CONFIG_PCI_DOMAINS_GENERIC
+- bus->domain_nr = pci_bus_find_domain_nr(bus, parent);
++ if (bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET)
++ bus->domain_nr = pci_bus_find_domain_nr(bus, parent);
++ else
++ bus->domain_nr = bridge->domain_nr;
+ #endif
+
+ b = pci_find_bus(pci_domain_nr(bus), bridge->busnr);
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 30bc462fb1964..a0fd1fe4189e4 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -538,6 +538,16 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
+ return (pdev->error_state != pci_channel_io_normal);
+ }
+
++/*
++ * Currently in ACPI spec, for each PCI host bridge, PCI Segment
++ * Group number is limited to a 16-bit value, therefore (int)-1 is
++ * not a valid PCI domain number, and can be used as a sentinel
++ * value indicating ->domain_nr is not set by the driver (and
++ * CONFIG_PCI_DOMAINS_GENERIC=y archs will set it with
++ * pci_bus_find_domain_nr()).
++ */
++#define PCI_DOMAIN_NR_NOT_SET (-1)
++
+ struct pci_host_bridge {
+ struct device dev;
+ struct pci_bus *bus; /* Root bus */
+@@ -545,6 +555,7 @@ struct pci_host_bridge {
+ struct pci_ops *child_ops;
+ void *sysdata;
+ int busnr;
++ int domain_nr;
+ struct list_head windows; /* resource_entry */
+ struct list_head dma_ranges; /* dma ranges resource list */
+ u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */
+--
+2.39.5
+
--- /dev/null
+From 9a4cc968fa1d50ae1ce704b5813a2e70f0fa1192 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Dec 2022 16:09:14 +0100
+Subject: platform: Provide a remove callback that returns no value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 5c5a7680e67ba6fbbb5f4d79fa41485450c1985c ]
+
+struct platform_driver::remove returning an integer made driver authors
+expect that returning an error code was proper error handling. However
+the driver core ignores the error and continues to remove the device
+because there is nothing the core could do anyhow and reentering the
+remove callback again is only calling for trouble.
+
+So this is an source for errors typically yielding resource leaks in the
+error path.
+
+As there are too many platform drivers to neatly convert them all to
+return void in a single go, do it in several steps after this patch:
+
+ a) Convert all drivers to implement .remove_new() returning void instead
+ of .remove() returning int;
+ b) Change struct platform_driver::remove() to return void and so make
+ it identical to .remove_new();
+ c) Change all drivers back to .remove() now with the better prototype;
+ d) drop struct platform_driver::remove_new().
+
+While this touches all drivers eventually twice, steps a) and c) can be
+done one driver after another and so reduces coordination efforts
+immensely and simplifies review.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Link: https://lore.kernel.org/r/20221209150914.3557650-1-u.kleine-koenig@pengutronix.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 276822a00db3 ("backlight: led_bl: Hold led_access lock when calling led_sysfs_disable()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/base/platform.c | 4 +++-
+ include/linux/platform_device.h | 11 +++++++++++
+ 2 files changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/base/platform.c b/drivers/base/platform.c
+index d0b15cbab0ff0..e07043d85c65c 100644
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -1306,7 +1306,9 @@ static int platform_remove(struct device *_dev)
+ struct platform_driver *drv = to_platform_driver(_dev->driver);
+ struct platform_device *dev = to_platform_device(_dev);
+
+- if (drv->remove) {
++ if (drv->remove_new) {
++ drv->remove_new(dev);
++ } else if (drv->remove) {
+ int ret = drv->remove(dev);
+
+ if (ret)
+diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
+index e7a83b0218077..870a918aa251c 100644
+--- a/include/linux/platform_device.h
++++ b/include/linux/platform_device.h
+@@ -203,7 +203,18 @@ extern void platform_device_put(struct platform_device *pdev);
+
+ struct platform_driver {
+ int (*probe)(struct platform_device *);
++
++ /*
++ * Traditionally the remove callback returned an int which however is
++ * ignored by the driver core. This led to wrong expectations by driver
++ * authors who thought returning an error code was a valid error
++ * handling strategy. To convert to a callback returning void, new
++ * drivers should implement .remove_new() until the conversion it done
++ * that eventually makes .remove() return void.
++ */
+ int (*remove)(struct platform_device *);
++ void (*remove_new)(struct platform_device *);
++
+ void (*shutdown)(struct platform_device *);
+ int (*suspend)(struct platform_device *, pm_message_t state);
+ int (*resume)(struct platform_device *);
+--
+2.39.5
+
--- /dev/null
+From abbdca9f84caf3e2493ec477b9387d3678e6f4ec Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Mar 2025 15:47:49 -0700
+Subject: platform/x86: ISST: Correct command storage data length
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+
+[ Upstream commit 9462e74c5c983cce34019bfb27f734552bebe59f ]
+
+After resume/online turbo limit ratio (TRL) is restored partially if
+the admin explicitly changed TRL from user space.
+
+A hash table is used to store SST mail box and MSR settings when modified
+to restore those settings after resume or online. This uses a struct
+isst_cmd field "data" to store these settings. This is a 64 bit field.
+But isst_store_new_cmd() is only assigning as u32. This results in
+truncation of 32 bits.
+
+Change the argument to u64 from u32.
+
+Fixes: f607874f35cb ("platform/x86: ISST: Restore state on resume")
+Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+Cc: stable@vger.kernel.org
+Link: https://lore.kernel.org/r/20250328224749.2691272-1-srinivas.pandruvada@linux.intel.com
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/intel_speed_select_if/isst_if_common.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_common.c b/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
+index 407afafc7e83f..e0f7368e7e3e9 100644
+--- a/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
++++ b/drivers/platform/x86/intel_speed_select_if/isst_if_common.c
+@@ -77,7 +77,7 @@ static DECLARE_HASHTABLE(isst_hash, 8);
+ static DEFINE_MUTEX(isst_hash_lock);
+
+ static int isst_store_new_cmd(int cmd, u32 cpu, int mbox_cmd_type, u32 param,
+- u32 data)
++ u64 data)
+ {
+ struct isst_cmd *sst_cmd;
+
+--
+2.39.5
+
--- /dev/null
+From c0a06ddf4d69e17c258ec4f171bdac9d6960254e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Apr 2025 17:42:32 +0100
+Subject: selftests/mm: generate a temporary mountpoint for cgroup filesystem
+
+From: Mark Brown <broonie@kernel.org>
+
+[ Upstream commit 9c02223e2d9df5cb37c51aedb78f3960294e09b5 ]
+
+Currently if the filesystem for the cgroups version it wants to use is not
+mounted charge_reserved_hugetlb.sh and hugetlb_reparenting_test.sh tests
+will attempt to mount it on the hard coded path /dev/cgroup/memory,
+deleting that directory when the test finishes. This will fail if there
+is not a preexisting directory at that path, and since the directory is
+deleted subsequent runs of the test will fail. Instead of relying on this
+hard coded directory name use mktemp to generate a temporary directory to
+use as a mountpoint, fixing both the assumption and the disruption caused
+by deleting a preexisting directory.
+
+This means that if the relevant cgroup filesystem is not already mounted
+then we rely on having coreutils (which provides mktemp) installed. I
+suspect that many current users are relying on having things automounted
+by default, and given that the script relies on bash it's probably not an
+unreasonable requirement.
+
+Link: https://lkml.kernel.org/r/20250404-kselftest-mm-cgroup2-detection-v1-1-3dba6d32ba8c@kernel.org
+Fixes: 209376ed2a84 ("selftests/vm: make charge_reserved_hugetlb.sh work with existing cgroup setting")
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Cc: Aishwarya TCV <aishwarya.tcv@arm.com>
+Cc: Mark Brown <broonie@kernel.org>
+Cc: Mina Almasry <almasrymina@google.com>
+Cc: Shuah Khan <shuah@kernel.org>
+Cc: Waiman Long <longman@redhat.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/selftests/vm/charge_reserved_hugetlb.sh | 4 ++--
+ tools/testing/selftests/vm/hugetlb_reparenting_test.sh | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/tools/testing/selftests/vm/charge_reserved_hugetlb.sh b/tools/testing/selftests/vm/charge_reserved_hugetlb.sh
+index 28192ec98498f..c44226b4e0bfb 100644
+--- a/tools/testing/selftests/vm/charge_reserved_hugetlb.sh
++++ b/tools/testing/selftests/vm/charge_reserved_hugetlb.sh
+@@ -24,7 +24,7 @@ fi
+ if [[ $cgroup2 ]]; then
+ cgroup_path=$(mount -t cgroup2 | head -1 | awk '{print $3}')
+ if [[ -z "$cgroup_path" ]]; then
+- cgroup_path=/dev/cgroup/memory
++ cgroup_path=$(mktemp -d)
+ mount -t cgroup2 none $cgroup_path
+ do_umount=1
+ fi
+@@ -32,7 +32,7 @@ if [[ $cgroup2 ]]; then
+ else
+ cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}')
+ if [[ -z "$cgroup_path" ]]; then
+- cgroup_path=/dev/cgroup/memory
++ cgroup_path=$(mktemp -d)
+ mount -t cgroup memory,hugetlb $cgroup_path
+ do_umount=1
+ fi
+diff --git a/tools/testing/selftests/vm/hugetlb_reparenting_test.sh b/tools/testing/selftests/vm/hugetlb_reparenting_test.sh
+index c665b16f1e370..a4123632942dd 100644
+--- a/tools/testing/selftests/vm/hugetlb_reparenting_test.sh
++++ b/tools/testing/selftests/vm/hugetlb_reparenting_test.sh
+@@ -19,7 +19,7 @@ fi
+ if [[ $cgroup2 ]]; then
+ CGROUP_ROOT=$(mount -t cgroup2 | head -1 | awk '{print $3}')
+ if [[ -z "$CGROUP_ROOT" ]]; then
+- CGROUP_ROOT=/dev/cgroup/memory
++ CGROUP_ROOT=$(mktemp -d)
+ mount -t cgroup2 none $CGROUP_ROOT
+ do_umount=1
+ fi
+--
+2.39.5
+
s390-dasd-fix-double-module-refcount-decrement.patch
pmdomain-ti-add-a-null-pointer-check-to-the-omap_prm_domain_init.patch
drivers-staging-rtl8723bs-fix-locking-in-rtw_scan_timeout_handler.patch
+platform-x86-isst-correct-command-storage-data-lengt.patch
+tracing-allow-synthetic-events-to-pass-around-stackt.patch
+tracing-fix-synth-event-printk-format-for-str-fields.patch
+media-streamzap-remove-unnecessary-ir_raw_event_rese.patch
+media-streamzap-no-need-for-usb-pid-vid-in-device-na.patch
+media-streamzap-less-chatter.patch
+media-streamzap-remove-unused-struct-members.patch
+media-streamzap-fix-race-between-device-disconnectio.patch
+media-venus-venc-init-the-session-only-once-in-queue.patch
+media-venus-limit-hfi-sessions-to-the-maximum-suppor.patch
+media-venus-hfi-correct-session-init-return-error.patch
+media-venus-pm_helpers-check-instance-state-when-cal.patch
+media-venus-create-hfi-platform-and-move-vpp-vsp-the.patch
+media-venus-rename-venus_caps-to-hfi_plat_caps.patch
+media-venus-hfi_plat-add-codecs-and-capabilities-ops.patch
+media-venus-get-codecs-and-capabilities-from-hfi-pla.patch
+media-venus-hfi_parser-refactor-hfi-packet-parsing-l.patch
+net-dsa-mv88e6xxx-fix-vtu-methods-for-6320-family.patch
+soc-samsung-exynos-chipid-initialize-later-with-arch.patch
+soc-samsung-exynos-chipid-convert-to-driver-and-merg.patch
+soc-samsung-exynos-chipid-avoid-soc_device_to_device.patch
+soc-samsung-exynos-chipid-pass-revision-reg-offsets.patch
+soc-samsung-exynos-chipid-add-null-pointer-check-in-.patch
+iio-adc-ad7768-1-move-setting-of-val-a-bit-later-to-.patch
+iio-adc-ad7768-1-fix-conversion-result-sign.patch
+driver-core-platform-reorder-functions.patch
+driver-core-platform-change-logic-implementing-platf.patch
+driver-core-platform-use-bus_type-functions.patch
+driver-core-platform-emit-a-warning-if-a-remove-call.patch
+platform-provide-a-remove-callback-that-returns-no-v.patch
+backlight-led_bl-convert-to-platform-remove-callback.patch
+backlight-led_bl-hold-led_access-lock-when-calling-l.patch
+cifs-print-tids-as-hex.patch
+cifs-avoid-null-pointer-dereference-in-dbg-call.patch
+pci-introduce-domain_nr-in-pci_host_bridge.patch
+pci-coalesce-host-bridge-contiguous-apertures.patch
+pci-assign-pci-domain-ids-by-ida_alloc.patch
+pci-fix-reference-leak-in-pci_register_host_bridge.patch
+selftests-mm-generate-a-temporary-mountpoint-for-cgr.patch
+drm-amd-amdgpu-amdgpu_vram_mgr-add-missing-descripti.patch
+drm-amdgpu-remove-amdgpu_device-arg-from-free_sgt-ap.patch
+drm-amdgpu-dma_buf-fix-page_link-check.patch
--- /dev/null
+From b002eeb638cdba75a661d928059e4770ce106557 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 15:35:18 -0600
+Subject: soc: samsung: exynos-chipid: Add NULL pointer check in
+ exynos_chipid_probe()
+
+From: Chenyuan Yang <chenyuan0y@gmail.com>
+
+[ Upstream commit c8222ef6cf29dd7cad21643228f96535cc02b327 ]
+
+soc_dev_attr->revision could be NULL, thus,
+a pointer check is added to prevent potential NULL pointer dereference.
+This is similar to the fix in commit 3027e7b15b02
+("ice: Fix some null pointer dereference issues in ice_ptp.c").
+
+This issue is found by our static analysis tool.
+
+Signed-off-by: Chenyuan Yang <chenyuan0y@gmail.com>
+Link: https://lore.kernel.org/r/20250212213518.69432-1-chenyuan0y@gmail.com
+Fixes: 3253b7b7cd44 ("soc: samsung: Add exynos chipid driver support")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/samsung/exynos-chipid.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
+index a2d163a1b4e11..fb9e80b63b917 100644
+--- a/drivers/soc/samsung/exynos-chipid.c
++++ b/drivers/soc/samsung/exynos-chipid.c
+@@ -124,6 +124,8 @@ static int exynos_chipid_probe(struct platform_device *pdev)
+
+ soc_dev_attr->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "%x", soc_info.revision);
++ if (!soc_dev_attr->revision)
++ return -ENOMEM;
+ soc_dev_attr->soc_id = product_id_to_soc_id(soc_info.product_id);
+ if (!soc_dev_attr->soc_id) {
+ pr_err("Unknown SoC\n");
+--
+2.39.5
+
--- /dev/null
+From 6e7007923ae880de6d1f758136d7cc00590e02cb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Sep 2021 11:31:12 +0200
+Subject: soc: samsung: exynos-chipid: avoid soc_device_to_device()
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+
+[ Upstream commit d1141886c8d72ad77920e6e4b617d366e6e3ee8a ]
+
+soc_device_to_device() seems to be discouraged [1] so remove it in favor
+of printing info message with platform device. This will only change
+the prefix in the info message from "soc soc0: " to "exynos-chipid
+10000000.chipid:".
+
+[1] https://lore.kernel.org/lkml/20191111052741.GB3176397@kroah.com/
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+Reviewed-by: Sylwester Nawrocki <snawrocki@kernel.org>
+Tested-by: Sylwester Nawrocki <snawrocki@kernel.org>
+Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com>
+Tested-by: Alim Akhtar <alim.akhtar@samsung.com>
+Link: https://lore.kernel.org/r/20210919093114.35987-2-krzysztof.kozlowski@canonical.com
+Stable-dep-of: c8222ef6cf29 ("soc: samsung: exynos-chipid: Add NULL pointer check in exynos_chipid_probe()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/samsung/exynos-chipid.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
+index 2ab6ce71e9be5..2b02af5d2faff 100644
+--- a/drivers/soc/samsung/exynos-chipid.c
++++ b/drivers/soc/samsung/exynos-chipid.c
+@@ -103,8 +103,7 @@ static int exynos_chipid_probe(struct platform_device *pdev)
+
+ platform_set_drvdata(pdev, soc_dev);
+
+- dev_info(soc_device_to_device(soc_dev),
+- "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
++ dev_info(&pdev->dev, "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
+ soc_dev_attr->soc_id, product_id, revision);
+
+ return 0;
+--
+2.39.5
+
--- /dev/null
+From 755165359792d34158f7497441d44801256b3472 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 7 Dec 2020 19:54:57 +0100
+Subject: soc: samsung: exynos-chipid: convert to driver and merge exynos-asv
+
+From: Krzysztof Kozlowski <krzk@kernel.org>
+
+[ Upstream commit 352bfbb3e0230c96b2bce00d2ac3f0de303cc7b6 ]
+
+The Exynos Chip ID driver on Exynos SoCs has so far only informational
+purpose - to expose the SoC device in sysfs. No other drivers depend on
+it so there is really no benefit of initializing it early.
+
+The code would be the most flexible if converted to a regular driver.
+However there is already another driver - Exynos ASV (Adaptive Supply
+Voltage) - which binds to the device node of Chip ID.
+
+The solution is to convert the Exynos Chip ID to a built in driver and
+merge the Exynos ASV into it.
+
+This has several benefits:
+1. Although the Exynos ASV driver binds to a device node present in all
+ Exynos DTS (generic compatible), it fails to probe except on the
+ supported ones (only Exynos5422). This means that the regular boot
+ process has a planned/normal device probe failure.
+
+ Merging the ASV into Chip ID will remove this probe failure because
+ the final driver will always bind, just with disabled ASV features.
+
+2. Allows to use dev_info() as the SoC bus is present (since
+ core_initcall).
+
+3. Could speed things up because of execution of Chip ID code in a SMP
+ environment (after bringing up secondary CPUs, unlike early_initcall),
+ This reduces the amount of work to be done early, when the kernel has
+ to bring up critical devices.
+
+5. Makes the Chip ID code defer-probe friendly,
+
+Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
+Link: https://lore.kernel.org/r/20201207190517.262051-5-krzk@kernel.org
+Reviewed-by: Pankaj Dubey <pankaj.dubey@samsung.com>
+Stable-dep-of: c8222ef6cf29 ("soc: samsung: exynos-chipid: Add NULL pointer check in exynos_chipid_probe()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm/mach-exynos/Kconfig | 1 -
+ drivers/soc/samsung/Kconfig | 12 +++--
+ drivers/soc/samsung/Makefile | 3 +-
+ drivers/soc/samsung/exynos-asv.c | 45 +++++--------------
+ drivers/soc/samsung/exynos-asv.h | 2 +
+ drivers/soc/samsung/exynos-chipid.c | 69 ++++++++++++++++++++---------
+ 6 files changed, 67 insertions(+), 65 deletions(-)
+
+diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
+index b5df98ee5d176..4b554cc8fa58a 100644
+--- a/arch/arm/mach-exynos/Kconfig
++++ b/arch/arm/mach-exynos/Kconfig
+@@ -13,7 +13,6 @@ menuconfig ARCH_EXYNOS
+ select ARM_GIC
+ select EXYNOS_IRQ_COMBINER
+ select COMMON_CLK_SAMSUNG
+- select EXYNOS_ASV
+ select EXYNOS_CHIPID
+ select EXYNOS_THERMAL
+ select EXYNOS_PMU
+diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig
+index fc7f48a922881..5745d7e5908e9 100644
+--- a/drivers/soc/samsung/Kconfig
++++ b/drivers/soc/samsung/Kconfig
+@@ -7,21 +7,19 @@ menuconfig SOC_SAMSUNG
+
+ if SOC_SAMSUNG
+
+-config EXYNOS_ASV
+- bool "Exynos Adaptive Supply Voltage support" if COMPILE_TEST
+- depends on (ARCH_EXYNOS && EXYNOS_CHIPID) || COMPILE_TEST
+- select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS
+-
+ # There is no need to enable these drivers for ARMv8
+ config EXYNOS_ASV_ARM
+ bool "Exynos ASV ARMv7-specific driver extensions" if COMPILE_TEST
+- depends on EXYNOS_ASV
++ depends on EXYNOS_CHIPID
+
+ config EXYNOS_CHIPID
+- bool "Exynos Chipid controller driver" if COMPILE_TEST
++ bool "Exynos ChipID controller and ASV driver" if COMPILE_TEST
+ depends on ARCH_EXYNOS || COMPILE_TEST
++ select EXYNOS_ASV_ARM if ARM && ARCH_EXYNOS
+ select MFD_SYSCON
+ select SOC_BUS
++ help
++ Support for Samsung Exynos SoC ChipID and Adaptive Supply Voltage.
+
+ config EXYNOS_PMU
+ bool "Exynos PMU controller driver" if COMPILE_TEST
+diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
+index 59e8e9453f27c..0c523a8de4ebf 100644
+--- a/drivers/soc/samsung/Makefile
++++ b/drivers/soc/samsung/Makefile
+@@ -1,9 +1,8 @@
+ # SPDX-License-Identifier: GPL-2.0
+
+-obj-$(CONFIG_EXYNOS_ASV) += exynos-asv.o
+ obj-$(CONFIG_EXYNOS_ASV_ARM) += exynos5422-asv.o
+
+-obj-$(CONFIG_EXYNOS_CHIPID) += exynos-chipid.o
++obj-$(CONFIG_EXYNOS_CHIPID) += exynos-chipid.o exynos-asv.o
+ obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o
+
+ obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \
+diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c
+index 5daeadc363829..d60af8acc3916 100644
+--- a/drivers/soc/samsung/exynos-asv.c
++++ b/drivers/soc/samsung/exynos-asv.c
+@@ -2,7 +2,9 @@
+ /*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
++ * Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org>
+ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
++ * Author: Krzysztof Kozlowski <krzk@kernel.org>
+ *
+ * Samsung Exynos SoC Adaptive Supply Voltage support
+ */
+@@ -10,12 +12,7 @@
+ #include <linux/cpu.h>
+ #include <linux/device.h>
+ #include <linux/errno.h>
+-#include <linux/init.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/module.h>
+ #include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/platform_device.h>
+ #include <linux/pm_opp.h>
+ #include <linux/regmap.h>
+ #include <linux/soc/samsung/exynos-chipid.h>
+@@ -111,7 +108,7 @@ static int exynos_asv_update_opps(struct exynos_asv *asv)
+ return 0;
+ }
+
+-static int exynos_asv_probe(struct platform_device *pdev)
++int exynos_asv_init(struct device *dev, struct regmap *regmap)
+ {
+ int (*probe_func)(struct exynos_asv *asv);
+ struct exynos_asv *asv;
+@@ -119,21 +116,16 @@ static int exynos_asv_probe(struct platform_device *pdev)
+ u32 product_id = 0;
+ int ret, i;
+
+- asv = devm_kzalloc(&pdev->dev, sizeof(*asv), GFP_KERNEL);
++ asv = devm_kzalloc(dev, sizeof(*asv), GFP_KERNEL);
+ if (!asv)
+ return -ENOMEM;
+
+- asv->chipid_regmap = device_node_to_regmap(pdev->dev.of_node);
+- if (IS_ERR(asv->chipid_regmap)) {
+- dev_err(&pdev->dev, "Could not find syscon regmap\n");
+- return PTR_ERR(asv->chipid_regmap);
+- }
+-
++ asv->chipid_regmap = regmap;
++ asv->dev = dev;
+ ret = regmap_read(asv->chipid_regmap, EXYNOS_CHIPID_REG_PRO_ID,
+ &product_id);
+ if (ret < 0) {
+- dev_err(&pdev->dev, "Cannot read revision from ChipID: %d\n",
+- ret);
++ dev_err(dev, "Cannot read revision from ChipID: %d\n", ret);
+ return -ENODEV;
+ }
+
+@@ -142,7 +134,9 @@ static int exynos_asv_probe(struct platform_device *pdev)
+ probe_func = exynos5422_asv_init;
+ break;
+ default:
+- return -ENODEV;
++ dev_dbg(dev, "No ASV support for this SoC\n");
++ devm_kfree(dev, asv);
++ return 0;
+ }
+
+ cpu_dev = get_cpu_device(0);
+@@ -150,14 +144,11 @@ static int exynos_asv_probe(struct platform_device *pdev)
+ if (ret < 0)
+ return -EPROBE_DEFER;
+
+- ret = of_property_read_u32(pdev->dev.of_node, "samsung,asv-bin",
++ ret = of_property_read_u32(dev->of_node, "samsung,asv-bin",
+ &asv->of_bin);
+ if (ret < 0)
+ asv->of_bin = -EINVAL;
+
+- asv->dev = &pdev->dev;
+- dev_set_drvdata(&pdev->dev, asv);
+-
+ for (i = 0; i < ARRAY_SIZE(asv->subsys); i++)
+ asv->subsys[i].asv = asv;
+
+@@ -167,17 +158,3 @@ static int exynos_asv_probe(struct platform_device *pdev)
+
+ return exynos_asv_update_opps(asv);
+ }
+-
+-static const struct of_device_id exynos_asv_of_device_ids[] = {
+- { .compatible = "samsung,exynos4210-chipid" },
+- {}
+-};
+-
+-static struct platform_driver exynos_asv_driver = {
+- .driver = {
+- .name = "exynos-asv",
+- .of_match_table = exynos_asv_of_device_ids,
+- },
+- .probe = exynos_asv_probe,
+-};
+-module_platform_driver(exynos_asv_driver);
+diff --git a/drivers/soc/samsung/exynos-asv.h b/drivers/soc/samsung/exynos-asv.h
+index 3fd1f2acd9995..dcbe154db31e0 100644
+--- a/drivers/soc/samsung/exynos-asv.h
++++ b/drivers/soc/samsung/exynos-asv.h
+@@ -68,4 +68,6 @@ static inline u32 exynos_asv_opp_get_frequency(const struct exynos_asv_subsys *s
+ return __asv_get_table_entry(&subsys->table, level, 0);
+ }
+
++int exynos_asv_init(struct device *dev, struct regmap *regmap);
++
+ #endif /* __LINUX_SOC_EXYNOS_ASV_H */
+diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
+index 0f2de1b016a59..2ab6ce71e9be5 100644
+--- a/drivers/soc/samsung/exynos-chipid.c
++++ b/drivers/soc/samsung/exynos-chipid.c
+@@ -2,20 +2,28 @@
+ /*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
++ * Copyright (c) 2020 Krzysztof Kozlowski <krzk@kernel.org>
+ *
+ * Exynos - CHIP ID support
+ * Author: Pankaj Dubey <pankaj.dubey@samsung.com>
+ * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
++ * Author: Krzysztof Kozlowski <krzk@kernel.org>
++ *
++ * Samsung Exynos SoC Adaptive Supply Voltage and Chip ID support
+ */
+
+-#include <linux/io.h>
++#include <linux/device.h>
++#include <linux/errno.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/of.h>
++#include <linux/platform_device.h>
+ #include <linux/regmap.h>
+ #include <linux/slab.h>
+ #include <linux/soc/samsung/exynos-chipid.h>
+ #include <linux/sys_soc.h>
+
++#include "exynos-asv.h"
++
+ static const struct exynos_soc_id {
+ const char *name;
+ unsigned int id;
+@@ -45,25 +53,17 @@ static const char * __init product_id_to_soc_id(unsigned int product_id)
+ return NULL;
+ }
+
+-static int __init exynos_chipid_early_init(void)
++static int exynos_chipid_probe(struct platform_device *pdev)
+ {
+ struct soc_device_attribute *soc_dev_attr;
+ struct soc_device *soc_dev;
+ struct device_node *root;
+- struct device_node *syscon;
+ struct regmap *regmap;
+ u32 product_id;
+ u32 revision;
+ int ret;
+
+- syscon = of_find_compatible_node(NULL, NULL,
+- "samsung,exynos4210-chipid");
+- if (!syscon)
+- return -ENODEV;
+-
+- regmap = device_node_to_regmap(syscon);
+- of_node_put(syscon);
+-
++ regmap = device_node_to_regmap(pdev->dev.of_node);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+@@ -73,7 +73,8 @@ static int __init exynos_chipid_early_init(void)
+
+ revision = product_id & EXYNOS_REV_MASK;
+
+- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
++ soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr),
++ GFP_KERNEL);
+ if (!soc_dev_attr)
+ return -ENOMEM;
+
+@@ -83,20 +84,24 @@ static int __init exynos_chipid_early_init(void)
+ of_property_read_string(root, "model", &soc_dev_attr->machine);
+ of_node_put(root);
+
+- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision);
++ soc_dev_attr->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL,
++ "%x", revision);
+ soc_dev_attr->soc_id = product_id_to_soc_id(product_id);
+ if (!soc_dev_attr->soc_id) {
+ pr_err("Unknown SoC\n");
+- ret = -ENODEV;
+- goto err;
++ return -ENODEV;
+ }
+
+ /* please note that the actual registration will be deferred */
+ soc_dev = soc_device_register(soc_dev_attr);
+- if (IS_ERR(soc_dev)) {
+- ret = PTR_ERR(soc_dev);
++ if (IS_ERR(soc_dev))
++ return PTR_ERR(soc_dev);
++
++ ret = exynos_asv_init(&pdev->dev, regmap);
++ if (ret)
+ goto err;
+- }
++
++ platform_set_drvdata(pdev, soc_dev);
+
+ dev_info(soc_device_to_device(soc_dev),
+ "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
+@@ -105,9 +110,31 @@ static int __init exynos_chipid_early_init(void)
+ return 0;
+
+ err:
+- kfree(soc_dev_attr->revision);
+- kfree(soc_dev_attr);
++ soc_device_unregister(soc_dev);
++
+ return ret;
+ }
+
+-arch_initcall(exynos_chipid_early_init);
++static int exynos_chipid_remove(struct platform_device *pdev)
++{
++ struct soc_device *soc_dev = platform_get_drvdata(pdev);
++
++ soc_device_unregister(soc_dev);
++
++ return 0;
++}
++
++static const struct of_device_id exynos_chipid_of_device_ids[] = {
++ { .compatible = "samsung,exynos4210-chipid" },
++ {}
++};
++
++static struct platform_driver exynos_chipid_driver = {
++ .driver = {
++ .name = "exynos-chipid",
++ .of_match_table = exynos_chipid_of_device_ids,
++ },
++ .probe = exynos_chipid_probe,
++ .remove = exynos_chipid_remove,
++};
++builtin_platform_driver(exynos_chipid_driver);
+--
+2.39.5
+
--- /dev/null
+From 5d8266c978cf8b7ac0930fcf1fc70a5d15541e47 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Dec 2020 21:59:55 +0200
+Subject: soc: samsung: exynos-chipid: initialize later - with arch_initcall
+
+From: Krzysztof Kozlowski <krzk@kernel.org>
+
+[ Upstream commit 3b4c362e5ef102ca2d70d33f4e8cf0780053a7db ]
+
+The Exynos ChipID driver on Exynos SoCs has only informational
+purpose - to expose the SoC device in sysfs. No other drivers
+depend on it so there is really no benefit of initializing it early.
+
+Instead, initialize everything with arch_initcall which:
+1. Allows to use dev_info() as the SoC bus is present (since
+ core_initcall),
+2. Could speed things up because of execution in a SMP environment
+ (after bringing up secondary CPUs, unlike early_initcall),
+3. Reduces the amount of work to be done early, when the kernel has to
+ bring up critical devices.
+
+Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
+Link: https://lore.kernel.org/r/20201202195955.128633-2-krzk@kernel.org
+Stable-dep-of: c8222ef6cf29 ("soc: samsung: exynos-chipid: Add NULL pointer check in exynos_chipid_probe()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/samsung/exynos-chipid.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
+index 8d4d050869068..0f2de1b016a59 100644
+--- a/drivers/soc/samsung/exynos-chipid.c
++++ b/drivers/soc/samsung/exynos-chipid.c
+@@ -98,9 +98,9 @@ static int __init exynos_chipid_early_init(void)
+ goto err;
+ }
+
+- /* it is too early to use dev_info() here (soc_dev is NULL) */
+- pr_info("soc soc0: Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
+- soc_dev_attr->soc_id, product_id, revision);
++ dev_info(soc_device_to_device(soc_dev),
++ "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
++ soc_dev_attr->soc_id, product_id, revision);
+
+ return 0;
+
+@@ -110,4 +110,4 @@ static int __init exynos_chipid_early_init(void)
+ return ret;
+ }
+
+-early_initcall(exynos_chipid_early_init);
++arch_initcall(exynos_chipid_early_init);
+--
+2.39.5
+
--- /dev/null
+From 2c0af2c4721c4f25b917681cb1eaeba5064a5489 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Oct 2021 16:35:06 +0300
+Subject: soc: samsung: exynos-chipid: Pass revision reg offsets
+
+From: Sam Protsenko <semen.protsenko@linaro.org>
+
+[ Upstream commit c072c4ef7ef09e1d6470c48cf52570487589b76a ]
+
+Old Exynos SoCs have both Product ID and Revision ID in one single
+register, while new SoCs tend to have two separate registers for those
+IDs. Implement handling of both cases by passing Revision ID register
+offsets in driver data.
+
+Previously existing macros for Exynos4210 (removed in this patch) were
+incorrect:
+
+ #define EXYNOS_SUBREV_MASK (0xf << 4)
+ #define EXYNOS_MAINREV_MASK (0xf << 0)
+
+Actual format of PRO_ID register in Exynos4210 (offset 0x0):
+
+ [31:12] Product ID
+ [9:8] Package information
+ [7:4] Main Revision Number
+ [3:0] Sub Revision Number
+
+This patch doesn't change the behavior on existing platforms, so
+'/sys/devices/soc0/revision' will show the same string as before.
+
+Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
+Tested-by: Henrik Grimler <henrik@grimler.se>
+Link: https://lore.kernel.org/r/20211014133508.1210-1-semen.protsenko@linaro.org
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+Stable-dep-of: c8222ef6cf29 ("soc: samsung: exynos-chipid: Add NULL pointer check in exynos_chipid_probe()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/soc/samsung/exynos-chipid.c | 69 +++++++++++++++++++----
+ include/linux/soc/samsung/exynos-chipid.h | 6 +-
+ 2 files changed, 60 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
+index 2b02af5d2faff..a2d163a1b4e11 100644
+--- a/drivers/soc/samsung/exynos-chipid.c
++++ b/drivers/soc/samsung/exynos-chipid.c
+@@ -16,6 +16,7 @@
+ #include <linux/errno.h>
+ #include <linux/mfd/syscon.h>
+ #include <linux/of.h>
++#include <linux/of_device.h>
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
+ #include <linux/slab.h>
+@@ -24,6 +25,17 @@
+
+ #include "exynos-asv.h"
+
++struct exynos_chipid_variant {
++ unsigned int rev_reg; /* revision register offset */
++ unsigned int main_rev_shift; /* main revision offset in rev_reg */
++ unsigned int sub_rev_shift; /* sub revision offset in rev_reg */
++};
++
++struct exynos_chipid_info {
++ u32 product_id;
++ u32 revision;
++};
++
+ static const struct exynos_soc_id {
+ const char *name;
+ unsigned int id;
+@@ -48,31 +60,57 @@ static const char * __init product_id_to_soc_id(unsigned int product_id)
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(soc_ids); i++)
+- if ((product_id & EXYNOS_MASK) == soc_ids[i].id)
++ if (product_id == soc_ids[i].id)
+ return soc_ids[i].name;
+ return NULL;
+ }
+
++static int exynos_chipid_get_chipid_info(struct regmap *regmap,
++ const struct exynos_chipid_variant *data,
++ struct exynos_chipid_info *soc_info)
++{
++ int ret;
++ unsigned int val, main_rev, sub_rev;
++
++ ret = regmap_read(regmap, EXYNOS_CHIPID_REG_PRO_ID, &val);
++ if (ret < 0)
++ return ret;
++ soc_info->product_id = val & EXYNOS_MASK;
++
++ if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) {
++ ret = regmap_read(regmap, data->rev_reg, &val);
++ if (ret < 0)
++ return ret;
++ }
++ main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK;
++ sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK;
++ soc_info->revision = (main_rev << EXYNOS_REV_PART_SHIFT) | sub_rev;
++
++ return 0;
++}
++
+ static int exynos_chipid_probe(struct platform_device *pdev)
+ {
++ const struct exynos_chipid_variant *drv_data;
++ struct exynos_chipid_info soc_info;
+ struct soc_device_attribute *soc_dev_attr;
+ struct soc_device *soc_dev;
+ struct device_node *root;
+ struct regmap *regmap;
+- u32 product_id;
+- u32 revision;
+ int ret;
+
++ drv_data = of_device_get_match_data(&pdev->dev);
++ if (!drv_data)
++ return -EINVAL;
++
+ regmap = device_node_to_regmap(pdev->dev.of_node);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+- ret = regmap_read(regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id);
++ ret = exynos_chipid_get_chipid_info(regmap, drv_data, &soc_info);
+ if (ret < 0)
+ return ret;
+
+- revision = product_id & EXYNOS_REV_MASK;
+-
+ soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr),
+ GFP_KERNEL);
+ if (!soc_dev_attr)
+@@ -85,8 +123,8 @@ static int exynos_chipid_probe(struct platform_device *pdev)
+ of_node_put(root);
+
+ soc_dev_attr->revision = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+- "%x", revision);
+- soc_dev_attr->soc_id = product_id_to_soc_id(product_id);
++ "%x", soc_info.revision);
++ soc_dev_attr->soc_id = product_id_to_soc_id(soc_info.product_id);
+ if (!soc_dev_attr->soc_id) {
+ pr_err("Unknown SoC\n");
+ return -ENODEV;
+@@ -104,7 +142,7 @@ static int exynos_chipid_probe(struct platform_device *pdev)
+ platform_set_drvdata(pdev, soc_dev);
+
+ dev_info(&pdev->dev, "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
+- soc_dev_attr->soc_id, product_id, revision);
++ soc_dev_attr->soc_id, soc_info.product_id, soc_info.revision);
+
+ return 0;
+
+@@ -123,9 +161,18 @@ static int exynos_chipid_remove(struct platform_device *pdev)
+ return 0;
+ }
+
++static const struct exynos_chipid_variant exynos4210_chipid_drv_data = {
++ .rev_reg = 0x0,
++ .main_rev_shift = 4,
++ .sub_rev_shift = 0,
++};
++
+ static const struct of_device_id exynos_chipid_of_device_ids[] = {
+- { .compatible = "samsung,exynos4210-chipid" },
+- {}
++ {
++ .compatible = "samsung,exynos4210-chipid",
++ .data = &exynos4210_chipid_drv_data,
++ },
++ { }
+ };
+
+ static struct platform_driver exynos_chipid_driver = {
+diff --git a/include/linux/soc/samsung/exynos-chipid.h b/include/linux/soc/samsung/exynos-chipid.h
+index 8bca6763f99c1..62f0e25310687 100644
+--- a/include/linux/soc/samsung/exynos-chipid.h
++++ b/include/linux/soc/samsung/exynos-chipid.h
+@@ -9,10 +9,8 @@
+ #define __LINUX_SOC_EXYNOS_CHIPID_H
+
+ #define EXYNOS_CHIPID_REG_PRO_ID 0x00
+-#define EXYNOS_SUBREV_MASK (0xf << 4)
+-#define EXYNOS_MAINREV_MASK (0xf << 0)
+-#define EXYNOS_REV_MASK (EXYNOS_SUBREV_MASK | \
+- EXYNOS_MAINREV_MASK)
++#define EXYNOS_REV_PART_MASK 0xf
++#define EXYNOS_REV_PART_SHIFT 4
+ #define EXYNOS_MASK 0xfffff000
+
+ #define EXYNOS_CHIPID_REG_PKG_ID 0x04
+--
+2.39.5
+
--- /dev/null
+From f85226030cd1bf402c8fde3022124a03c07b1db1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jan 2023 10:21:28 -0500
+Subject: tracing: Allow synthetic events to pass around stacktraces
+
+From: Steven Rostedt (Google) <rostedt@goodmis.org>
+
+[ Upstream commit 00cf3d672a9dd409418647e9f98784c339c3ff63 ]
+
+Allow a stacktrace from one event to be displayed by the end event of a
+synthetic event. This is very useful when looking for the longest latency
+of a sleep or something blocked on I/O.
+
+ # cd /sys/kernel/tracing/
+ # echo 's:block_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events
+ # echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace if prev_state == 1||prev_state == 2' > events/sched/sched_switch/trigger
+ # echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(block_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger
+
+The above creates a "block_lat" synthetic event that take the stacktrace of
+when a task schedules out in either the interruptible or uninterruptible
+states, and on a new per process max $delta (the time it was scheduled
+out), will print the process id and the stacktrace.
+
+ # echo 1 > events/synthetic/block_lat/enable
+ # cat trace
+ # TASK-PID CPU# ||||| TIMESTAMP FUNCTION
+ # | | | ||||| | |
+ kworker/u16:0-767 [006] d..4. 560.645045: block_lat: pid=767 delta=66 stack=STACK:
+ => __schedule
+ => schedule
+ => pipe_read
+ => vfs_read
+ => ksys_read
+ => do_syscall_64
+ => 0x966000aa
+
+ <idle>-0 [003] d..4. 561.132117: block_lat: pid=0 delta=413787 stack=STACK:
+ => __schedule
+ => schedule
+ => schedule_hrtimeout_range_clock
+ => do_sys_poll
+ => __x64_sys_poll
+ => do_syscall_64
+ => 0x966000aa
+
+ <...>-153 [006] d..4. 562.068407: block_lat: pid=153 delta=54 stack=STACK:
+ => __schedule
+ => schedule
+ => io_schedule
+ => rq_qos_wait
+ => wbt_wait
+ => __rq_qos_throttle
+ => blk_mq_submit_bio
+ => submit_bio_noacct_nocheck
+ => ext4_bio_write_page
+ => mpage_submit_page
+ => mpage_process_page_bufs
+ => mpage_prepare_extent_to_map
+ => ext4_do_writepages
+ => ext4_writepages
+ => do_writepages
+ => __writeback_single_inode
+
+Link: https://lkml.kernel.org/r/20230117152236.010941267@goodmis.org
+
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Tom Zanussi <zanussi@kernel.org>
+Cc: Ross Zwisler <zwisler@google.com>
+Cc: Ching-lin Yu <chinglinyu@google.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: 4d38328eb442 ("tracing: Fix synth event printk format for str fields")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace.h | 4 ++
+ kernel/trace/trace_events_hist.c | 7 ++-
+ kernel/trace/trace_events_synth.c | 80 ++++++++++++++++++++++++++++++-
+ kernel/trace/trace_synth.h | 1 +
+ 4 files changed, 87 insertions(+), 5 deletions(-)
+
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 7c90872f2435d..f47938d8401a2 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -109,6 +109,10 @@ enum trace_type {
+ unlikely(__ret_warn_once); \
+ })
+
++#define HIST_STACKTRACE_DEPTH 16
++#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
++#define HIST_STACKTRACE_SKIP 5
++
+ /*
+ * syscalls are special, and need special handling, this is why
+ * they are not included in trace_entries.h
+diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
+index 059a106e62bec..a0342b45a06da 100644
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -282,10 +282,6 @@ DEFINE_HIST_FIELD_FN(u8);
+ #define for_each_hist_key_field(i, hist_data) \
+ for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
+
+-#define HIST_STACKTRACE_DEPTH 16
+-#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
+-#define HIST_STACKTRACE_SKIP 5
+-
+ #define HITCOUNT_IDX 0
+ #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE)
+
+@@ -3356,6 +3352,9 @@ static int check_synth_field(struct synth_event *event,
+ && field->is_dynamic)
+ return 0;
+
++ if (strstr(hist_field->type, "long[") && field->is_stack)
++ return 0;
++
+ if (strcmp(field->type, hist_field->type) != 0) {
+ if (field->size != hist_field->size ||
+ (!field->is_string && field->is_signed != hist_field->is_signed))
+diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
+index e43426aa12830..4878758ceea2a 100644
+--- a/kernel/trace/trace_events_synth.c
++++ b/kernel/trace/trace_events_synth.c
+@@ -162,6 +162,14 @@ static int synth_field_is_string(char *type)
+ return false;
+ }
+
++static int synth_field_is_stack(char *type)
++{
++ if (strstr(type, "long[") != NULL)
++ return true;
++
++ return false;
++}
++
+ static int synth_field_string_size(char *type)
+ {
+ char buf[4], *end, *start;
+@@ -237,6 +245,8 @@ static int synth_field_size(char *type)
+ size = sizeof(gfp_t);
+ else if (synth_field_is_string(type))
+ size = synth_field_string_size(type);
++ else if (synth_field_is_stack(type))
++ size = 0;
+
+ return size;
+ }
+@@ -281,6 +291,8 @@ static const char *synth_field_fmt(char *type)
+ fmt = "%x";
+ else if (synth_field_is_string(type))
+ fmt = "%.*s";
++ else if (synth_field_is_stack(type))
++ fmt = "%s";
+
+ return fmt;
+ }
+@@ -360,6 +372,23 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter,
+ i == se->n_fields - 1 ? "" : " ");
+ n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
+ }
++ } else if (se->fields[i]->is_stack) {
++ u32 offset, data_offset, len;
++ unsigned long *p, *end;
++
++ offset = (u32)entry->fields[n_u64];
++ data_offset = offset & 0xffff;
++ len = offset >> 16;
++
++ p = (void *)entry + data_offset;
++ end = (void *)p + len - (sizeof(long) - 1);
++
++ trace_seq_printf(s, "%s=STACK:\n", se->fields[i]->name);
++
++ for (; *p && p < end; p++)
++ trace_seq_printf(s, "=> %pS\n", (void *)*p);
++ n_u64++;
++
+ } else {
+ struct trace_print_flags __flags[] = {
+ __def_gfpflag_names, {-1, NULL} };
+@@ -427,6 +456,43 @@ static unsigned int trace_string(struct synth_trace_event *entry,
+ return len;
+ }
+
++static unsigned int trace_stack(struct synth_trace_event *entry,
++ struct synth_event *event,
++ long *stack,
++ unsigned int data_size,
++ unsigned int *n_u64)
++{
++ unsigned int len;
++ u32 data_offset;
++ void *data_loc;
++
++ data_offset = struct_size(entry, fields, event->n_u64);
++ data_offset += data_size;
++
++ for (len = 0; len < HIST_STACKTRACE_DEPTH; len++) {
++ if (!stack[len])
++ break;
++ }
++
++ /* Include the zero'd element if it fits */
++ if (len < HIST_STACKTRACE_DEPTH)
++ len++;
++
++ len *= sizeof(long);
++
++ /* Find the dynamic section to copy the stack into. */
++ data_loc = (void *)entry + data_offset;
++ memcpy(data_loc, stack, len);
++
++ /* Fill in the field that holds the offset/len combo */
++ data_offset |= len << 16;
++ *(u32 *)&entry->fields[*n_u64] = data_offset;
++
++ (*n_u64)++;
++
++ return len;
++}
++
+ static notrace void trace_event_raw_event_synth(void *__data,
+ u64 *var_ref_vals,
+ unsigned int *var_ref_idx)
+@@ -479,6 +545,12 @@ static notrace void trace_event_raw_event_synth(void *__data,
+ event->fields[i]->is_dynamic,
+ data_size, &n_u64);
+ data_size += len; /* only dynamic string increments */
++ } if (event->fields[i]->is_stack) {
++ long *stack = (long *)(long)var_ref_vals[val_idx];
++
++ len = trace_stack(entry, event, stack,
++ data_size, &n_u64);
++ data_size += len;
+ } else {
+ struct synth_field *field = event->fields[i];
+ u64 val = var_ref_vals[val_idx];
+@@ -541,6 +613,9 @@ static int __set_synth_event_print_fmt(struct synth_event *event,
+ event->fields[i]->is_dynamic)
+ pos += snprintf(buf + pos, LEN_OR_ZERO,
+ ", __get_str(%s)", event->fields[i]->name);
++ else if (event->fields[i]->is_stack)
++ pos += snprintf(buf + pos, LEN_OR_ZERO,
++ ", __get_stacktrace(%s)", event->fields[i]->name);
+ else
+ pos += snprintf(buf + pos, LEN_OR_ZERO,
+ ", REC->%s", event->fields[i]->name);
+@@ -660,7 +735,8 @@ static struct synth_field *parse_synth_field(int argc, const char **argv,
+ ret = -EINVAL;
+ goto free;
+ } else if (size == 0) {
+- if (synth_field_is_string(field->type)) {
++ if (synth_field_is_string(field->type) ||
++ synth_field_is_stack(field->type)) {
+ char *type;
+
+ len = sizeof("__data_loc ") + strlen(field->type) + 1;
+@@ -691,6 +767,8 @@ static struct synth_field *parse_synth_field(int argc, const char **argv,
+
+ if (synth_field_is_string(field->type))
+ field->is_string = true;
++ else if (synth_field_is_stack(field->type))
++ field->is_stack = true;
+
+ field->is_signed = synth_field_signed(field->type);
+ out:
+diff --git a/kernel/trace/trace_synth.h b/kernel/trace/trace_synth.h
+index 4007fe95cf42c..077c748a8b3a6 100644
+--- a/kernel/trace/trace_synth.h
++++ b/kernel/trace/trace_synth.h
+@@ -18,6 +18,7 @@ struct synth_field {
+ bool is_signed;
+ bool is_string;
+ bool is_dynamic;
++ bool is_stack;
+ };
+
+ struct synth_event {
+--
+2.39.5
+
--- /dev/null
+From df3e73ad1909a8e4ae012c85b8b55abae2885bee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Mar 2025 16:52:02 +0000
+Subject: tracing: Fix synth event printk format for str fields
+
+From: Douglas Raillard <douglas.raillard@arm.com>
+
+[ Upstream commit 4d38328eb442dc06aec4350fd9594ffa6488af02 ]
+
+The printk format for synth event uses "%.*s" to print string fields,
+but then only passes the pointer part as var arg.
+
+Replace %.*s with %s as the C string is guaranteed to be null-terminated.
+
+The output in print fmt should never have been updated as __get_str()
+handles the string limit because it can access the length of the string in
+the string meta data that is saved in the ring buffer.
+
+Cc: stable@vger.kernel.org
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Fixes: 8db4d6bfbbf92 ("tracing: Change synthetic event string format to limit printed length")
+Link: https://lore.kernel.org/20250325165202.541088-1-douglas.raillard@arm.com
+Signed-off-by: Douglas Raillard <douglas.raillard@arm.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace_events_synth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
+index 4878758ceea2a..613d45e7b608d 100644
+--- a/kernel/trace/trace_events_synth.c
++++ b/kernel/trace/trace_events_synth.c
+@@ -290,7 +290,7 @@ static const char *synth_field_fmt(char *type)
+ else if (strcmp(type, "gfp_t") == 0)
+ fmt = "%x";
+ else if (synth_field_is_string(type))
+- fmt = "%.*s";
++ fmt = "%s";
+ else if (synth_field_is_stack(type))
+ fmt = "%s";
+
+--
+2.39.5
+