+++ /dev/null
-From 41f6bf84ed6284cd845a30ca86dd991cc20e21a8 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 22 Nov 2024 15:30:26 -0800
-Subject: dmaengine: idxd: Add idxd_device_config_save() and
- idxd_device_config_restore() helpers
-
-From: Fenghua Yu <fenghua.yu@intel.com>
-
-[ Upstream commit 6078a315aec15e0776fa90347cf4eba7478cdbd7 ]
-
-Add the helpers to save and restore IDXD device configurations.
-
-These helpers will be called during Function Level Reset (FLR) processing.
-
-Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
-Reviewed-by: Dave Jiang <dave.jiang@intel.com>
-Link: https://lore.kernel.org/r/20241122233028.2762809-4-fenghua.yu@intel.com
-Signed-off-by: Vinod Koul <vkoul@kernel.org>
-Stable-dep-of: ee66bc295783 ("dmaengine: idxd: Fix leaking event log memory")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/dma/idxd/idxd.h | 11 ++
- drivers/dma/idxd/init.c | 225 ++++++++++++++++++++++++++++++++++++++++
- 2 files changed, 236 insertions(+)
-
-diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
-index 1f93dd6db28f0..8b381a1fb2595 100644
---- a/drivers/dma/idxd/idxd.h
-+++ b/drivers/dma/idxd/idxd.h
-@@ -374,6 +374,17 @@ struct idxd_device {
- struct dentry *dbgfs_evl_file;
-
- bool user_submission_safe;
-+
-+ struct idxd_saved_states *idxd_saved;
-+};
-+
-+struct idxd_saved_states {
-+ struct idxd_device saved_idxd;
-+ struct idxd_evl saved_evl;
-+ struct idxd_engine **saved_engines;
-+ struct idxd_wq **saved_wqs;
-+ struct idxd_group **saved_groups;
-+ unsigned long *saved_wq_enable_map;
- };
-
- static inline unsigned int evl_ent_size(struct idxd_device *idxd)
-diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
-index 795e408ba2d50..f6bbc95eeb925 100644
---- a/drivers/dma/idxd/init.c
-+++ b/drivers/dma/idxd/init.c
-@@ -833,6 +833,231 @@ static void idxd_unbind(struct device_driver *drv, const char *buf)
- put_device(dev);
- }
-
-+#define idxd_free_saved_configs(saved_configs, count) \
-+ do { \
-+ int i; \
-+ \
-+ for (i = 0; i < (count); i++) \
-+ kfree(saved_configs[i]); \
-+ } while (0)
-+
-+static void idxd_free_saved(struct idxd_group **saved_groups,
-+ struct idxd_engine **saved_engines,
-+ struct idxd_wq **saved_wqs,
-+ struct idxd_device *idxd)
-+{
-+ if (saved_groups)
-+ idxd_free_saved_configs(saved_groups, idxd->max_groups);
-+ if (saved_engines)
-+ idxd_free_saved_configs(saved_engines, idxd->max_engines);
-+ if (saved_wqs)
-+ idxd_free_saved_configs(saved_wqs, idxd->max_wqs);
-+}
-+
-+/*
-+ * Save IDXD device configurations including engines, groups, wqs etc.
-+ * The saved configurations can be restored when needed.
-+ */
-+static int idxd_device_config_save(struct idxd_device *idxd,
-+ struct idxd_saved_states *idxd_saved)
-+{
-+ struct device *dev = &idxd->pdev->dev;
-+ int i;
-+
-+ memcpy(&idxd_saved->saved_idxd, idxd, sizeof(*idxd));
-+
-+ if (idxd->evl) {
-+ memcpy(&idxd_saved->saved_evl, idxd->evl,
-+ sizeof(struct idxd_evl));
-+ }
-+
-+ struct idxd_group **saved_groups __free(kfree) =
-+ kcalloc_node(idxd->max_groups,
-+ sizeof(struct idxd_group *),
-+ GFP_KERNEL, dev_to_node(dev));
-+ if (!saved_groups)
-+ return -ENOMEM;
-+
-+ for (i = 0; i < idxd->max_groups; i++) {
-+ struct idxd_group *saved_group __free(kfree) =
-+ kzalloc_node(sizeof(*saved_group), GFP_KERNEL,
-+ dev_to_node(dev));
-+
-+ if (!saved_group) {
-+ /* Free saved groups */
-+ idxd_free_saved(saved_groups, NULL, NULL, idxd);
-+
-+ return -ENOMEM;
-+ }
-+
-+ memcpy(saved_group, idxd->groups[i], sizeof(*saved_group));
-+ saved_groups[i] = no_free_ptr(saved_group);
-+ }
-+
-+ struct idxd_engine **saved_engines =
-+ kcalloc_node(idxd->max_engines,
-+ sizeof(struct idxd_engine *),
-+ GFP_KERNEL, dev_to_node(dev));
-+ if (!saved_engines) {
-+ /* Free saved groups */
-+ idxd_free_saved(saved_groups, NULL, NULL, idxd);
-+
-+ return -ENOMEM;
-+ }
-+ for (i = 0; i < idxd->max_engines; i++) {
-+ struct idxd_engine *saved_engine __free(kfree) =
-+ kzalloc_node(sizeof(*saved_engine), GFP_KERNEL,
-+ dev_to_node(dev));
-+ if (!saved_engine) {
-+ /* Free saved groups and engines */
-+ idxd_free_saved(saved_groups, saved_engines, NULL,
-+ idxd);
-+
-+ return -ENOMEM;
-+ }
-+
-+ memcpy(saved_engine, idxd->engines[i], sizeof(*saved_engine));
-+ saved_engines[i] = no_free_ptr(saved_engine);
-+ }
-+
-+ unsigned long *saved_wq_enable_map __free(bitmap) =
-+ bitmap_zalloc_node(idxd->max_wqs, GFP_KERNEL,
-+ dev_to_node(dev));
-+ if (!saved_wq_enable_map) {
-+ /* Free saved groups and engines */
-+ idxd_free_saved(saved_groups, saved_engines, NULL, idxd);
-+
-+ return -ENOMEM;
-+ }
-+
-+ bitmap_copy(saved_wq_enable_map, idxd->wq_enable_map, idxd->max_wqs);
-+
-+ struct idxd_wq **saved_wqs __free(kfree) =
-+ kcalloc_node(idxd->max_wqs, sizeof(struct idxd_wq *),
-+ GFP_KERNEL, dev_to_node(dev));
-+ if (!saved_wqs) {
-+ /* Free saved groups and engines */
-+ idxd_free_saved(saved_groups, saved_engines, NULL, idxd);
-+
-+ return -ENOMEM;
-+ }
-+
-+ for (i = 0; i < idxd->max_wqs; i++) {
-+ struct idxd_wq *saved_wq __free(kfree) =
-+ kzalloc_node(sizeof(*saved_wq), GFP_KERNEL,
-+ dev_to_node(dev));
-+ struct idxd_wq *wq;
-+
-+ if (!saved_wq) {
-+ /* Free saved groups, engines, and wqs */
-+ idxd_free_saved(saved_groups, saved_engines, saved_wqs,
-+ idxd);
-+
-+ return -ENOMEM;
-+ }
-+
-+ if (!test_bit(i, saved_wq_enable_map))
-+ continue;
-+
-+ wq = idxd->wqs[i];
-+ mutex_lock(&wq->wq_lock);
-+ memcpy(saved_wq, wq, sizeof(*saved_wq));
-+ saved_wqs[i] = no_free_ptr(saved_wq);
-+ mutex_unlock(&wq->wq_lock);
-+ }
-+
-+ /* Save configurations */
-+ idxd_saved->saved_groups = no_free_ptr(saved_groups);
-+ idxd_saved->saved_engines = no_free_ptr(saved_engines);
-+ idxd_saved->saved_wq_enable_map = no_free_ptr(saved_wq_enable_map);
-+ idxd_saved->saved_wqs = no_free_ptr(saved_wqs);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Restore IDXD device configurations including engines, groups, wqs etc
-+ * that were saved before.
-+ */
-+static void idxd_device_config_restore(struct idxd_device *idxd,
-+ struct idxd_saved_states *idxd_saved)
-+{
-+ struct idxd_evl *saved_evl = &idxd_saved->saved_evl;
-+ int i;
-+
-+ idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit;
-+
-+ if (saved_evl)
-+ idxd->evl->size = saved_evl->size;
-+
-+ for (i = 0; i < idxd->max_groups; i++) {
-+ struct idxd_group *saved_group, *group;
-+
-+ saved_group = idxd_saved->saved_groups[i];
-+ group = idxd->groups[i];
-+
-+ group->rdbufs_allowed = saved_group->rdbufs_allowed;
-+ group->rdbufs_reserved = saved_group->rdbufs_reserved;
-+ group->tc_a = saved_group->tc_a;
-+ group->tc_b = saved_group->tc_b;
-+ group->use_rdbuf_limit = saved_group->use_rdbuf_limit;
-+
-+ kfree(saved_group);
-+ }
-+ kfree(idxd_saved->saved_groups);
-+
-+ for (i = 0; i < idxd->max_engines; i++) {
-+ struct idxd_engine *saved_engine, *engine;
-+
-+ saved_engine = idxd_saved->saved_engines[i];
-+ engine = idxd->engines[i];
-+
-+ engine->group = saved_engine->group;
-+
-+ kfree(saved_engine);
-+ }
-+ kfree(idxd_saved->saved_engines);
-+
-+ bitmap_copy(idxd->wq_enable_map, idxd_saved->saved_wq_enable_map,
-+ idxd->max_wqs);
-+ bitmap_free(idxd_saved->saved_wq_enable_map);
-+
-+ for (i = 0; i < idxd->max_wqs; i++) {
-+ struct idxd_wq *saved_wq, *wq;
-+ size_t len;
-+
-+ if (!test_bit(i, idxd->wq_enable_map))
-+ continue;
-+
-+ saved_wq = idxd_saved->saved_wqs[i];
-+ wq = idxd->wqs[i];
-+
-+ mutex_lock(&wq->wq_lock);
-+
-+ wq->group = saved_wq->group;
-+ wq->flags = saved_wq->flags;
-+ wq->threshold = saved_wq->threshold;
-+ wq->size = saved_wq->size;
-+ wq->priority = saved_wq->priority;
-+ wq->type = saved_wq->type;
-+ len = strlen(saved_wq->name) + 1;
-+ strscpy(wq->name, saved_wq->name, len);
-+ wq->max_xfer_bytes = saved_wq->max_xfer_bytes;
-+ wq->max_batch_size = saved_wq->max_batch_size;
-+ wq->enqcmds_retries = saved_wq->enqcmds_retries;
-+ wq->descs = saved_wq->descs;
-+ wq->idxd_chan = saved_wq->idxd_chan;
-+ len = strlen(saved_wq->driver_name) + 1;
-+ strscpy(wq->driver_name, saved_wq->driver_name, len);
-+
-+ mutex_unlock(&wq->wq_lock);
-+
-+ kfree(saved_wq);
-+ }
-+
-+ kfree(idxd_saved->saved_wqs);
-+}
-+
- /*
- * Probe idxd PCI device.
- * If idxd is not given, need to allocate idxd and set up its data.
---
-2.53.0
-
+++ /dev/null
-From b57b47af4c4f5b2b73d018b29edb9752eeaf18d3 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 22 Nov 2024 15:30:25 -0800
-Subject: dmaengine: idxd: Binding and unbinding IDXD device and driver
-
-From: Fenghua Yu <fenghua.yu@intel.com>
-
-[ Upstream commit 3ab45516772b813315324dc63a900703144e80c4 ]
-
-Add idxd_bind() and idxd_unbind() helpers to bind and unbind the IDXD
-device and driver.
-
-These helpers will be called during Function Level Reset (FLR) processing.
-
-Signed-off-by: Fenghua Yu <fenghua.yu@intel.com>
-Reviewed-by: Dave Jiang <dave.jiang@intel.com>
-Link: https://lore.kernel.org/r/20241122233028.2762809-3-fenghua.yu@intel.com
-Signed-off-by: Vinod Koul <vkoul@kernel.org>
-Stable-dep-of: ee66bc295783 ("dmaengine: idxd: Fix leaking event log memory")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/dma/idxd/init.c | 33 +++++++++++++++++++++++++++++++++
- 1 file changed, 33 insertions(+)
-
-diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
-index c3073518d1db4..795e408ba2d50 100644
---- a/drivers/dma/idxd/init.c
-+++ b/drivers/dma/idxd/init.c
-@@ -800,6 +800,39 @@ static void idxd_cleanup(struct idxd_device *idxd)
- idxd_disable_sva(idxd->pdev);
- }
-
-+/*
-+ * Attach IDXD device to IDXD driver.
-+ */
-+static int idxd_bind(struct device_driver *drv, const char *buf)
-+{
-+ const struct bus_type *bus = drv->bus;
-+ struct device *dev;
-+ int err = -ENODEV;
-+
-+ dev = bus_find_device_by_name(bus, NULL, buf);
-+ if (dev)
-+ err = device_driver_attach(drv, dev);
-+
-+ put_device(dev);
-+
-+ return err;
-+}
-+
-+/*
-+ * Detach IDXD device from driver.
-+ */
-+static void idxd_unbind(struct device_driver *drv, const char *buf)
-+{
-+ const struct bus_type *bus = drv->bus;
-+ struct device *dev;
-+
-+ dev = bus_find_device_by_name(bus, NULL, buf);
-+ if (dev && dev->driver == drv)
-+ device_release_driver(dev);
-+
-+ put_device(dev);
-+}
-+
- /*
- * Probe idxd PCI device.
- * If idxd is not given, need to allocate idxd and set up its data.
---
-2.53.0
-
+++ /dev/null
-From 782eee4212c814e2146563aadb10f1b7c03e8002 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 21 Jan 2026 10:34:28 -0800
-Subject: dmaengine: idxd: Fix crash when the event log is disabled
-
-From: Vinicius Costa Gomes <vinicius.gomes@intel.com>
-
-[ Upstream commit 52d2edea0d63c935e82631e4b9e4a94eccf97b5b ]
-
-If reporting errors to the event log is not supported by the hardware,
-and an error that causes Function Level Reset (FLR) is received, the
-driver will try to restore the event log even if it was not allocated.
-
-Also, only try to free the event log if it was properly allocated.
-
-Fixes: 6078a315aec1 ("dmaengine: idxd: Add idxd_device_config_save() and idxd_device_config_restore() helpers")
-Reviewed-by: Dave Jiang <dave.jiang@intel.com>
-Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
-Link: https://patch.msgid.link/20260121-idxd-fix-flr-on-kernel-queues-v3-v3-2-7ed70658a9d1@intel.com
-Signed-off-by: Vinod Koul <vkoul@kernel.org>
-Stable-dep-of: ee66bc295783 ("dmaengine: idxd: Fix leaking event log memory")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/dma/idxd/device.c | 3 +++
- drivers/dma/idxd/init.c | 3 ++-
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
-index d8e0a12f62ace..4b32f7890e02a 100644
---- a/drivers/dma/idxd/device.c
-+++ b/drivers/dma/idxd/device.c
-@@ -815,6 +815,9 @@ static void idxd_device_evl_free(struct idxd_device *idxd)
- struct device *dev = &idxd->pdev->dev;
- struct idxd_evl *evl = idxd->evl;
-
-+ if (!evl)
-+ return;
-+
- gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
- if (!gencfg.evl_en)
- return;
-diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
-index 0f9003dd342d6..3655f340876c4 100644
---- a/drivers/dma/idxd/init.c
-+++ b/drivers/dma/idxd/init.c
-@@ -987,7 +987,8 @@ static void idxd_device_config_restore(struct idxd_device *idxd,
-
- idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit;
-
-- idxd->evl->size = saved_evl->size;
-+ if (idxd->evl)
-+ idxd->evl->size = saved_evl->size;
-
- for (i = 0; i < idxd->max_groups; i++) {
- struct idxd_group *saved_group, *group;
---
-2.53.0
-