* [PATCH 03/10] dmaengine: fsldma: convert to platform_get_irq_optional()
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
Replace the per-controller irq_of_parse_and_map() call with
platform_get_irq_optional(). The controller IRQ is optional — when
absent (-ENXIO) the driver falls back to per-channel IRQs. Any other
error is treated as fatal. The corresponding irq_dispose_mapping()
calls in the probe error path and remove function are removed.
The per-channel IRQ mapping in fsl_dma_chan_probe() uses a child
device_node rather than the platform device's of_node, so it is not
converted here.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/fsldma.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 89b88447be1b..0d28f8299bf8 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1206,7 +1206,6 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
static void fsl_dma_chan_remove(struct fsldma_chan *chan)
{
tasklet_kill(&chan->tasklet);
- irq_dispose_mapping(chan->irq);
list_del(&chan->common.device_node);
iounmap(chan->regs);
kfree(chan);
@@ -1239,7 +1238,14 @@ static int fsldma_of_probe(struct platform_device *op)
}
/* map the channel IRQ if it exists, but don't hookup the handler yet */
- fdev->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ fdev->irq = platform_get_irq_optional(op, 0);
+ if (fdev->irq < 0) {
+ if (fdev->irq != -ENXIO) {
+ err = fdev->irq;
+ goto out_iounmap;
+ }
+ fdev->irq = 0;
+ }
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
@@ -1305,7 +1311,7 @@ static int fsldma_of_probe(struct platform_device *op)
if (fdev->chan[i])
fsl_dma_chan_remove(fdev->chan[i]);
}
- irq_dispose_mapping(fdev->irq);
+out_iounmap:
iounmap(fdev->regs);
out_free:
kfree(fdev);
@@ -1327,7 +1333,6 @@ static void fsldma_of_remove(struct platform_device *op)
if (fdev->chan[i])
fsl_dma_chan_remove(fdev->chan[i]);
}
- irq_dispose_mapping(fdev->irq);
iounmap(fdev->regs);
kfree(fdev);
--
2.54.0
^ permalink raw reply related
* [PATCH 04/10] dmaengine: fsldma: convert to devm_kzalloc and fix error path
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
Convert fdev allocation from kzalloc_obj to devm_kzalloc to simplify
the probe error and remove paths by dropping the explicit kfree.
While at it, fix a goto target mismatch introduced in the recent
platform_get_irq_optional() conversion: goto err_iounmap should
be goto out_iounmap.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/fsldma.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 0d28f8299bf8..2efa16d12679 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1213,18 +1213,17 @@ static void fsl_dma_chan_remove(struct fsldma_chan *chan)
static int fsldma_of_probe(struct platform_device *op)
{
+ struct device *dev = &op->dev;
struct fsldma_device *fdev;
struct device_node *child;
unsigned int i;
int err;
- fdev = kzalloc_obj(*fdev);
- if (!fdev) {
- err = -ENOMEM;
- goto out_return;
- }
+ fdev = devm_kzalloc(dev, sizeof(*fdev), GFP_KERNEL);
+ if (!fdev)
+ return -ENOMEM;
- fdev->dev = &op->dev;
+ fdev->dev = dev;
INIT_LIST_HEAD(&fdev->common.channels);
/* The DMA address bits supported for this device. */
fdev->addr_bits = (long)device_get_match_data(fdev->dev);
@@ -1233,8 +1232,7 @@ static int fsldma_of_probe(struct platform_device *op)
fdev->regs = of_iomap(op->dev.of_node, 0);
if (!fdev->regs) {
dev_err(&op->dev, "unable to ioremap registers\n");
- err = -ENOMEM;
- goto out_free;
+ return -ENOMEM;
}
/* map the channel IRQ if it exists, but don't hookup the handler yet */
@@ -1313,9 +1311,6 @@ static int fsldma_of_probe(struct platform_device *op)
}
out_iounmap:
iounmap(fdev->regs);
-out_free:
- kfree(fdev);
-out_return:
return err;
}
@@ -1335,7 +1330,6 @@ static void fsldma_of_remove(struct platform_device *op)
}
iounmap(fdev->regs);
- kfree(fdev);
}
#ifdef CONFIG_PM
--
2.54.0
^ permalink raw reply related
* [PATCH 05/10] dmaengine: fsldma: convert ioremap to devm_platform_ioremap_resource
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
Convert of_iomap to devm_platform_ioremap_resource to let the devm
framework handle unmapping. This allows removing the out_iounmap
label, out_return label, and the explicit iounmap in both the probe
error path and the remove function.
The DGSR (fdev->regs) and per-channel registers (chan->regs) map
physically distinct regions in all supported variants
(EloPlus/Elo/Elo3), so there is no overlap risk.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/fsldma.c | 16 +++++-----------
1 file changed, 5 insertions(+), 11 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 2efa16d12679..2a6a247761a4 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1229,19 +1229,17 @@ static int fsldma_of_probe(struct platform_device *op)
fdev->addr_bits = (long)device_get_match_data(fdev->dev);
/* ioremap the registers for use */
- fdev->regs = of_iomap(op->dev.of_node, 0);
- if (!fdev->regs) {
+ fdev->regs = devm_platform_ioremap_resource(op, 0);
+ if (IS_ERR(fdev->regs)) {
dev_err(&op->dev, "unable to ioremap registers\n");
- return -ENOMEM;
+ return PTR_ERR(fdev->regs);
}
/* map the channel IRQ if it exists, but don't hookup the handler yet */
fdev->irq = platform_get_irq_optional(op, 0);
if (fdev->irq < 0) {
- if (fdev->irq != -ENXIO) {
- err = fdev->irq;
- goto out_iounmap;
- }
+ if (fdev->irq != -ENXIO)
+ return fdev->irq;
fdev->irq = 0;
}
@@ -1309,8 +1307,6 @@ static int fsldma_of_probe(struct platform_device *op)
if (fdev->chan[i])
fsl_dma_chan_remove(fdev->chan[i]);
}
-out_iounmap:
- iounmap(fdev->regs);
return err;
}
@@ -1328,8 +1324,6 @@ static void fsldma_of_remove(struct platform_device *op)
if (fdev->chan[i])
fsl_dma_chan_remove(fdev->chan[i]);
}
-
- iounmap(fdev->regs);
}
#ifdef CONFIG_PM
--
2.54.0
^ permalink raw reply related
* [PATCH 06/10] dmaengine: fsldma: convert channel allocation to devm_kzalloc
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
Convert fsl_dma_chan_probe from kzalloc_obj to devm_kzalloc, tying
the channel lifetime to the parent DMA device. This removes the
need for kfree(chan) in both the probe error path and the remove
function.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/fsldma.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 2a6a247761a4..ee6e595c2972 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1111,11 +1111,9 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
int err;
/* alloc channel */
- chan = kzalloc_obj(*chan);
- if (!chan) {
- err = -ENOMEM;
- goto out_return;
- }
+ chan = devm_kzalloc(fdev->dev, sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
/* ioremap registers for use */
chan->regs = of_iomap(node, 0);
@@ -1197,9 +1195,6 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
out_iounmap_regs:
iounmap(chan->regs);
-out_free_chan:
- kfree(chan);
-out_return:
return err;
}
@@ -1208,7 +1203,6 @@ static void fsl_dma_chan_remove(struct fsldma_chan *chan)
tasklet_kill(&chan->tasklet);
list_del(&chan->common.device_node);
iounmap(chan->regs);
- kfree(chan);
}
static int fsldma_of_probe(struct platform_device *op)
--
2.54.0
^ permalink raw reply related
* [PATCH 07/10] dmaengine: fsldma: convert channel ioremap to devm_of_iomap
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
Replace of_iomap with devm_of_iomap for per-channel register
mappings. This eliminates the iounmap calls in both the probe
error path and fsl_dma_chan_remove, and simplifies the error
handling by returning directly on failure.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/fsldma.c | 20 ++++++--------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index ee6e595c2972..0d73ce3dbfe6 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1108,7 +1108,6 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
{
struct fsldma_chan *chan;
struct resource res;
- int err;
/* alloc channel */
chan = devm_kzalloc(fdev->dev, sizeof(*chan), GFP_KERNEL);
@@ -1116,17 +1115,16 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
return -ENOMEM;
/* ioremap registers for use */
- chan->regs = of_iomap(node, 0);
- if (!chan->regs) {
+ chan->regs = devm_of_iomap(fdev->dev, node, 0, NULL);
+ if (IS_ERR(chan->regs)) {
dev_err(fdev->dev, "unable to ioremap registers\n");
- err = -ENOMEM;
- goto out_free_chan;
+ return PTR_ERR(chan->regs);
}
- err = of_address_to_resource(node, 0, &res);
+ int err = of_address_to_resource(node, 0, &res);
if (err) {
dev_err(fdev->dev, "unable to find 'reg' property\n");
- goto out_iounmap_regs;
+ return err;
}
chan->feature = feature;
@@ -1145,8 +1143,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
((res.start - 0x200) & 0xfff) >> 7;
if (chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) {
dev_err(fdev->dev, "too many channels for device\n");
- err = -EINVAL;
- goto out_iounmap_regs;
+ return -EINVAL;
}
fdev->chan[chan->id] = chan;
@@ -1192,17 +1189,12 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
chan->irq ? chan->irq : fdev->irq);
return 0;
-
-out_iounmap_regs:
- iounmap(chan->regs);
- return err;
}
static void fsl_dma_chan_remove(struct fsldma_chan *chan)
{
tasklet_kill(&chan->tasklet);
list_del(&chan->common.device_node);
- iounmap(chan->regs);
}
static int fsldma_of_probe(struct platform_device *op)
--
2.54.0
^ permalink raw reply related
* [PATCH 08/10] dmaengine: fsldma: replace irq_of_parse_and_map with of_irq_get
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
Use of_irq_get which returns a negative error code on failure
instead of silently returning 0. Update the IRQ validation checks
in fsldma_request_irqs from !chan->irq to chan->irq <= 0 to handle
both 0 and negative error returns correctly.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/fsldma.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 0d73ce3dbfe6..79a268139b9f 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1067,7 +1067,7 @@ static int fsldma_request_irqs(struct fsldma_device *fdev)
if (!chan)
continue;
- if (!chan->irq) {
+ if (chan->irq <= 0) {
chan_err(chan, "interrupts property missing in device tree\n");
ret = -ENODEV;
goto out_unwind;
@@ -1090,7 +1090,7 @@ static int fsldma_request_irqs(struct fsldma_device *fdev)
if (!chan)
continue;
- if (!chan->irq)
+ if (chan->irq <= 0)
continue;
free_irq(chan->irq, chan);
@@ -1180,7 +1180,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
dma_cookie_init(&chan->common);
/* find the IRQ line, if it exists in the device tree */
- chan->irq = irq_of_parse_and_map(node, 0);
+ chan->irq = of_irq_get(node, 0);
/* Add the channel to DMA device channel list */
list_add_tail(&chan->common.device_node, &fdev->common.channels);
--
2.54.0
^ permalink raw reply related
* [PATCH 09/10] dmaengine: fsldma: convert to devm_request_irq
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
Replace request_irq/free_irq with devm_request_irq, tying IRQ
lifetimes to the parent DMA device. This removes fsldma_free_irqs()
entirely, eliminates the out_unwind error unwind label, and drops
the explicit free_irq call from fsldma_of_remove.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/fsldma.c | 50 ++++++--------------------------------------
1 file changed, 6 insertions(+), 44 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 79a268139b9f..01c9cd27e795 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1027,26 +1027,6 @@ static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
return IRQ_RETVAL(handled);
}
-static void fsldma_free_irqs(struct fsldma_device *fdev)
-{
- struct fsldma_chan *chan;
- int i;
-
- if (fdev->irq) {
- dev_dbg(fdev->dev, "free per-controller IRQ\n");
- free_irq(fdev->irq, fdev);
- return;
- }
-
- for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
- chan = fdev->chan[i];
- if (chan && chan->irq) {
- chan_dbg(chan, "free per-channel IRQ\n");
- free_irq(chan->irq, chan);
- }
- }
-}
-
static int fsldma_request_irqs(struct fsldma_device *fdev)
{
struct fsldma_chan *chan;
@@ -1056,9 +1036,8 @@ static int fsldma_request_irqs(struct fsldma_device *fdev)
/* if we have a per-controller IRQ, use that */
if (fdev->irq) {
dev_dbg(fdev->dev, "request per-controller IRQ\n");
- ret = request_irq(fdev->irq, fsldma_ctrl_irq, IRQF_SHARED,
- "fsldma-controller", fdev);
- return ret;
+ return devm_request_irq(fdev->dev, fdev->irq, fsldma_ctrl_irq,
+ IRQF_SHARED, "fsldma-controller", fdev);
}
/* no per-controller IRQ, use the per-channel IRQs */
@@ -1069,34 +1048,19 @@ static int fsldma_request_irqs(struct fsldma_device *fdev)
if (chan->irq <= 0) {
chan_err(chan, "interrupts property missing in device tree\n");
- ret = -ENODEV;
- goto out_unwind;
+ return -ENODEV;
}
chan_dbg(chan, "request per-channel IRQ\n");
- ret = request_irq(chan->irq, fsldma_chan_irq, IRQF_SHARED,
- "fsldma-chan", chan);
+ ret = devm_request_irq(fdev->dev, chan->irq, fsldma_chan_irq,
+ IRQF_SHARED, "fsldma-chan", chan);
if (ret) {
chan_err(chan, "unable to request per-channel IRQ\n");
- goto out_unwind;
+ return ret;
}
}
return 0;
-
-out_unwind:
- for (/* none */; i >= 0; i--) {
- chan = fdev->chan[i];
- if (!chan)
- continue;
-
- if (chan->irq <= 0)
- continue;
-
- free_irq(chan->irq, chan);
- }
-
- return ret;
}
/*----------------------------------------------------------------------------*/
@@ -1304,8 +1268,6 @@ static void fsldma_of_remove(struct platform_device *op)
fdev = platform_get_drvdata(op);
dma_async_device_unregister(&fdev->common);
- fsldma_free_irqs(fdev);
-
for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) {
if (fdev->chan[i])
fsl_dma_chan_remove(fdev->chan[i]);
--
2.54.0
^ permalink raw reply related
* [PATCH 10/10] dmaengine: fsldma: replace ppc-specific accessors with portable generic ones
From: Rosen Penev @ 2026-06-05 22:01 UTC (permalink / raw)
To: dmaengine
Cc: Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
- Convert remaining in_be32/in_le32 calls to FSL_DMA_IN macro
- Replace __ilog2 with generic ilog2 (pull in linux/log2.h)
- Add linux/io.h include
- Expand non-PPC accessor support from ARM-only to all architectures
- Guard 64-bit generic accessors with CONFIG_64BIT; provide
emulation using 32-bit accessors on 32-bit platforms
Add COMPILE_TEST support as a result for extra compile coverage.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/dma/Kconfig | 2 +-
drivers/dma/fsldma.c | 11 ++++++-----
drivers/dma/fsldma.h | 35 ++++++++++++++++++++++++++++++++---
3 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 302021540d76..9b13e7aa31c7 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -206,7 +206,7 @@ config EP93XX_DMA
config FSL_DMA
tristate "Freescale Elo series DMA support"
- depends on FSL_SOC
+ depends on FSL_SOC || COMPILE_TEST
select DMA_ENGINE
select ASYNC_TX_ENABLE_CHANNEL_SWITCH
help
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 01c9cd27e795..a7c1f1b4c9ac 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -32,6 +32,8 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/log2.h>
#include <linux/fsldma.h>
#include "dmaengine.h"
#include "fsldma.h"
@@ -266,7 +268,7 @@ static void fsl_chan_set_src_loop_size(struct fsldma_chan *chan, int size)
case 4:
case 8:
mode &= ~FSL_DMA_MR_SAHTS_MASK;
- mode |= FSL_DMA_MR_SAHE | (__ilog2(size) << 14);
+ mode |= FSL_DMA_MR_SAHE | (ilog2(size) << 14);
break;
}
@@ -299,7 +301,7 @@ static void fsl_chan_set_dst_loop_size(struct fsldma_chan *chan, int size)
case 4:
case 8:
mode &= ~FSL_DMA_MR_DAHTS_MASK;
- mode |= FSL_DMA_MR_DAHE | (__ilog2(size) << 16);
+ mode |= FSL_DMA_MR_DAHE | (ilog2(size) << 16);
break;
}
@@ -326,7 +328,7 @@ static void fsl_chan_set_request_count(struct fsldma_chan *chan, int size)
mode = get_mr(chan);
mode &= ~FSL_DMA_MR_BWC_MASK;
- mode |= (__ilog2(size) << 24) & FSL_DMA_MR_BWC_MASK;
+ mode |= (ilog2(size) << 24) & FSL_DMA_MR_BWC_MASK;
set_mr(chan, mode);
}
@@ -1004,8 +1006,7 @@ static irqreturn_t fsldma_ctrl_irq(int irq, void *data)
u32 gsr, mask;
int i;
- gsr = (fdev->feature & FSL_DMA_BIG_ENDIAN) ? in_be32(fdev->regs)
- : in_le32(fdev->regs);
+ gsr = FSL_DMA_IN(fdev, fdev->regs, 32);
mask = 0xff000000;
dev_dbg(fdev->dev, "IRQ: gsr 0x%.8x\n", gsr);
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index d7b7a3138b85..01f93123b233 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -232,17 +232,46 @@ static void fsl_iowrite64be(u64 val, u64 __iomem *addr)
out_be32((u32 __iomem *)addr + 1, (u32)val);
}
#endif
-#endif
-
-#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
+#else
#define fsl_ioread32(p) ioread32(p)
#define fsl_ioread32be(p) ioread32be(p)
#define fsl_iowrite32(v, p) iowrite32(v, p)
#define fsl_iowrite32be(v, p) iowrite32be(v, p)
+
+#ifdef CONFIG_64BIT
#define fsl_ioread64(p) ioread64(p)
#define fsl_ioread64be(p) ioread64be(p)
#define fsl_iowrite64(v, p) iowrite64(v, p)
#define fsl_iowrite64be(v, p) iowrite64be(v, p)
+#else
+static inline u64 fsl_ioread64(const u64 __iomem *addr)
+{
+ u32 val_lo = ioread32((u32 __iomem *)addr);
+ u32 val_hi = ioread32((u32 __iomem *)addr + 1);
+
+ return ((u64)val_hi << 32) + val_lo;
+}
+
+static inline void fsl_iowrite64(u64 val, u64 __iomem *addr)
+{
+ iowrite32(val >> 32, (u32 __iomem *)addr + 1);
+ iowrite32((u32)val, (u32 __iomem *)addr);
+}
+
+static inline u64 fsl_ioread64be(const u64 __iomem *addr)
+{
+ u32 val_hi = ioread32be((u32 __iomem *)addr);
+ u32 val_lo = ioread32be((u32 __iomem *)addr + 1);
+
+ return ((u64)val_hi << 32) + val_lo;
+}
+
+static inline void fsl_iowrite64be(u64 val, u64 __iomem *addr)
+{
+ iowrite32be(val >> 32, (u32 __iomem *)addr);
+ iowrite32be((u32)val, (u32 __iomem *)addr + 1);
+}
+#endif
#endif
#define FSL_DMA_IN(fsl_dma, addr, width) \
--
2.54.0
^ permalink raw reply related
* Re: [PATCH 01/10] dmaengine: fsldma: kill tasklet before removing channel
From: Frank Li @ 2026-06-05 22:29 UTC (permalink / raw)
To: Rosen Penev
Cc: dmaengine, Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-2-rosenp@gmail.com>
On Fri, Jun 05, 2026 at 03:01:25PM -0700, Rosen Penev wrote:
>
> Add tasklet_kill() in fsl_dma_chan_remove() to prevent a race
> where the tasklet, scheduled by the IRQ handler, runs after
> the channel has been torn down. With the recent devm conversions
> the channel struct is no longer freed in the remove path, so
> this is not a use-after-free crash fix, but rather correct
> shutdown sequencing to avoid the tasklet operating on a
> logically-removed channel.
Use below commit should be enough, needn't talk about use-after-free
Call tasklet_kill() in fsl_dma_chan_remove() to prevent a race where a
tasklet scheduled from the IRQ handler can run after the channel has been
torn down.
Frank
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/dma/fsldma.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> index 22d62d958abd..0e2f84862261 100644
> --- a/drivers/dma/fsldma.c
> +++ b/drivers/dma/fsldma.c
> @@ -1205,6 +1205,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
>
> static void fsl_dma_chan_remove(struct fsldma_chan *chan)
> {
> + tasklet_kill(&chan->tasklet);
> irq_dispose_mapping(chan->irq);
> list_del(&chan->common.device_node);
> iounmap(chan->regs);
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH 00/10] dmaengine: fsldma: devm conversion, fixups, and cleanups
From: Frank Li @ 2026-06-05 22:36 UTC (permalink / raw)
To: Rosen Penev
Cc: dmaengine, Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-1-rosenp@gmail.com>
On Fri, Jun 05, 2026 at 03:01:24PM -0700, Rosen Penev wrote:
>
> Convert the Freescale Elo DMA driver to use managed device resources
> (devm), simplifying probe error handling and the remove path by
> dropping explicit iounmap, kfree, and free_irq calls.
>
> While doing so, fix a few issues uncovered along the way:
>
> - Kill the channel tasklet before removal to prevent a race with
> the IRQ handler.
> - Check the return value of dma_async_device_register() instead
> of silently returning success.
> - Replace the powerpc-specific I/O accessors with portable
> generic ones so the driver can be built on non-powerpc
> architectures.
>
> Build-tested with LLVM=1 ARCH=powerpc allmodconfig.
Suppose this v2, please add V2 at subject after [PATCH v2 ...]
Add change log here or each patch after --- to show what change in new version
Frank
>
> Rosen Penev (10):
> dmaengine: fsldma: kill tasklet before removing channel
> dmaengine: fsldma: check dma_async_device_register() return value
> dmaengine: fsldma: convert to platform_get_irq_optional()
> dmaengine: fsldma: convert to devm_kzalloc and fix error path
> dmaengine: fsldma: convert ioremap to devm_platform_ioremap_resource
> dmaengine: fsldma: convert channel allocation to devm_kzalloc
> dmaengine: fsldma: convert channel ioremap to devm_of_iomap
> dmaengine: fsldma: replace irq_of_parse_and_map with of_irq_get
> dmaengine: fsldma: convert to devm_request_irq
> dmaengine: fsldma: replace ppc-specific accessors with portable
> generic ones
>
> drivers/dma/Kconfig | 2 +-
> drivers/dma/fsldma.c | 139 +++++++++++++------------------------------
> drivers/dma/fsldma.h | 35 ++++++++++-
> 3 files changed, 76 insertions(+), 100 deletions(-)
>
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH 05/10] dmaengine: fsldma: convert ioremap to devm_platform_ioremap_resource
From: Frank Li @ 2026-06-05 22:41 UTC (permalink / raw)
To: Rosen Penev
Cc: dmaengine, Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-6-rosenp@gmail.com>
On Fri, Jun 05, 2026 at 03:01:29PM -0700, Rosen Penev wrote:
>
> Convert of_iomap to devm_platform_ioremap_resource to let the devm
> framework handle unmapping. This allows removing the out_iounmap
> label, out_return label, and the explicit iounmap in both the probe
> error path and the remove function.
>
> The DGSR (fdev->regs) and per-channel registers (chan->regs) map
> physically distinct regions in all supported variants
> (EloPlus/Elo/Elo3), so there is no overlap risk.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/dma/fsldma.c | 16 +++++-----------
> 1 file changed, 5 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> index 2efa16d12679..2a6a247761a4 100644
> --- a/drivers/dma/fsldma.c
> +++ b/drivers/dma/fsldma.c
> @@ -1229,19 +1229,17 @@ static int fsldma_of_probe(struct platform_device *op)
> fdev->addr_bits = (long)device_get_match_data(fdev->dev);
>
> /* ioremap the registers for use */
> - fdev->regs = of_iomap(op->dev.of_node, 0);
> - if (!fdev->regs) {
> + fdev->regs = devm_platform_ioremap_resource(op, 0);
> + if (IS_ERR(fdev->regs)) {
> dev_err(&op->dev, "unable to ioremap registers\n");
> - return -ENOMEM;
> + return PTR_ERR(fdev->regs);
> }
devm_platform_ioremap_resource() should print error message, so you can
remove above dev_err() also
Frank
>
> /* map the channel IRQ if it exists, but don't hookup the handler yet */
> fdev->irq = platform_get_irq_optional(op, 0);
> if (fdev->irq < 0) {
> - if (fdev->irq != -ENXIO) {
> - err = fdev->irq;
> - goto out_iounmap;
> - }
> + if (fdev->irq != -ENXIO)
> + return fdev->irq;
> fdev->irq = 0;
> }
>
> @@ -1309,8 +1307,6 @@ static int fsldma_of_probe(struct platform_device *op)
> if (fdev->chan[i])
> fsl_dma_chan_remove(fdev->chan[i]);
> }
> -out_iounmap:
> - iounmap(fdev->regs);
> return err;
> }
>
> @@ -1328,8 +1324,6 @@ static void fsldma_of_remove(struct platform_device *op)
> if (fdev->chan[i])
> fsl_dma_chan_remove(fdev->chan[i]);
> }
> -
> - iounmap(fdev->regs);
> }
>
> #ifdef CONFIG_PM
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH 04/10] dmaengine: fsldma: convert to devm_kzalloc and fix error path
From: Frank Li @ 2026-06-05 22:43 UTC (permalink / raw)
To: Rosen Penev
Cc: dmaengine, Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-5-rosenp@gmail.com>
On Fri, Jun 05, 2026 at 03:01:28PM -0700, Rosen Penev wrote:
>
> Convert fdev allocation from kzalloc_obj to devm_kzalloc to simplify
> the probe error and remove paths by dropping the explicit kfree.
>
> While at it, fix a goto target mismatch introduced in the recent
> platform_get_irq_optional() conversion: goto err_iounmap should
> be goto out_iounmap.
you should fix it at platform_get_irq_optional() conversion patch
Frank
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/dma/fsldma.c | 18 ++++++------------
> 1 file changed, 6 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> index 0d28f8299bf8..2efa16d12679 100644
> --- a/drivers/dma/fsldma.c
> +++ b/drivers/dma/fsldma.c
> @@ -1213,18 +1213,17 @@ static void fsl_dma_chan_remove(struct fsldma_chan *chan)
>
> static int fsldma_of_probe(struct platform_device *op)
> {
> + struct device *dev = &op->dev;
> struct fsldma_device *fdev;
> struct device_node *child;
> unsigned int i;
> int err;
>
> - fdev = kzalloc_obj(*fdev);
> - if (!fdev) {
> - err = -ENOMEM;
> - goto out_return;
> - }
> + fdev = devm_kzalloc(dev, sizeof(*fdev), GFP_KERNEL);
> + if (!fdev)
> + return -ENOMEM;
>
> - fdev->dev = &op->dev;
> + fdev->dev = dev;
> INIT_LIST_HEAD(&fdev->common.channels);
> /* The DMA address bits supported for this device. */
> fdev->addr_bits = (long)device_get_match_data(fdev->dev);
> @@ -1233,8 +1232,7 @@ static int fsldma_of_probe(struct platform_device *op)
> fdev->regs = of_iomap(op->dev.of_node, 0);
> if (!fdev->regs) {
> dev_err(&op->dev, "unable to ioremap registers\n");
> - err = -ENOMEM;
> - goto out_free;
> + return -ENOMEM;
> }
>
> /* map the channel IRQ if it exists, but don't hookup the handler yet */
> @@ -1313,9 +1311,6 @@ static int fsldma_of_probe(struct platform_device *op)
> }
> out_iounmap:
> iounmap(fdev->regs);
> -out_free:
> - kfree(fdev);
> -out_return:
> return err;
> }
>
> @@ -1335,7 +1330,6 @@ static void fsldma_of_remove(struct platform_device *op)
> }
>
> iounmap(fdev->regs);
> - kfree(fdev);
> }
>
> #ifdef CONFIG_PM
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH 07/10] dmaengine: fsldma: convert channel ioremap to devm_of_iomap
From: Frank Li @ 2026-06-05 22:49 UTC (permalink / raw)
To: Rosen Penev
Cc: dmaengine, Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-8-rosenp@gmail.com>
On Fri, Jun 05, 2026 at 03:01:31PM -0700, Rosen Penev wrote:
>
> Replace of_iomap with devm_of_iomap for per-channel register
all funcation need (), devm_of_iomap(), please check subject and other
patches
> mappings. This eliminates the iounmap calls in both the probe
Needn't "This", just, Eeliminate the eliminates()
> error path and fsl_dma_chan_remove, and simplifies the error
> handling by returning directly on failure.
commit message allow 75 chars each line, can you wrap it at 75 to reduce
line number.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/dma/fsldma.c | 20 ++++++--------------
> 1 file changed, 6 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> index ee6e595c2972..0d73ce3dbfe6 100644
> --- a/drivers/dma/fsldma.c
> +++ b/drivers/dma/fsldma.c
> @@ -1108,7 +1108,6 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
> {
> struct fsldma_chan *chan;
> struct resource res;
> - int err;
>
> /* alloc channel */
> chan = devm_kzalloc(fdev->dev, sizeof(*chan), GFP_KERNEL);
> @@ -1116,17 +1115,16 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
> return -ENOMEM;
>
> /* ioremap registers for use */
> - chan->regs = of_iomap(node, 0);
> - if (!chan->regs) {
> + chan->regs = devm_of_iomap(fdev->dev, node, 0, NULL);
> + if (IS_ERR(chan->regs)) {
> dev_err(fdev->dev, "unable to ioremap registers\n");
> - err = -ENOMEM;
> - goto out_free_chan;
> + return PTR_ERR(chan->regs);
dev_err follow return use
return dev_err_probe()
Frank
> }
>
> - err = of_address_to_resource(node, 0, &res);
> + int err = of_address_to_resource(node, 0, &res);
> if (err) {
> dev_err(fdev->dev, "unable to find 'reg' property\n");
> - goto out_iounmap_regs;
> + return err;
> }
>
> chan->feature = feature;
> @@ -1145,8 +1143,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
> ((res.start - 0x200) & 0xfff) >> 7;
> if (chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) {
> dev_err(fdev->dev, "too many channels for device\n");
> - err = -EINVAL;
> - goto out_iounmap_regs;
> + return -EINVAL;
> }
>
> fdev->chan[chan->id] = chan;
> @@ -1192,17 +1189,12 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
> chan->irq ? chan->irq : fdev->irq);
>
> return 0;
> -
> -out_iounmap_regs:
> - iounmap(chan->regs);
> - return err;
> }
>
> static void fsl_dma_chan_remove(struct fsldma_chan *chan)
> {
> tasklet_kill(&chan->tasklet);
> list_del(&chan->common.device_node);
> - iounmap(chan->regs);
> }
>
> static int fsldma_of_probe(struct platform_device *op)
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v6 01/20] s390: Expose protected virtualization through cc_platform_has()
From: JAEHOON KIM @ 2026-06-06 0:34 UTC (permalink / raw)
To: Aneesh Kumar K.V (Arm), iommu, linux-arm-kernel, linux-kernel,
linux-coco
Cc: Robin Murphy, Marek Szyprowski, Will Deacon, Marc Zyngier,
Steven Price, Suzuki K Poulose, Catalin Marinas, Jiri Pirko,
Jason Gunthorpe, Mostafa Saleh, Petr Tesarik,
Alexey Kardashevskiy, Dan Williams, Xu Yilun, linuxppc-dev,
linux-s390, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, x86, Halil Pasic,
Matthew Rosato
In-Reply-To: <20260604083959.1265923-2-aneesh.kumar@kernel.org>
On 6/4/2026 3:39 AM, Aneesh Kumar K.V (Arm) wrote:
> Protected virtualization guests use memory encryption, so advertise that to
> the rest of the kernel through cc_platform_has(CC_ATTR_MEM_ENCRYPT).
>
> s390 already forces DMA mappings to be unencrypted for protected
> virtualization guests through force_dma_unencrypted(). Add
> ARCH_HAS_CC_PLATFORM and provide the matching cc_platform_has()
> implementation
>
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
Tested-by: Jaehoon Kim <jhkim@linux.ibm.com>
Tested on s390 PV guest with swiotlb_dynamic configuration. SWIOTLB
bounce buffer allocation and dynamic pool management work correctly.
Also concurrent I/O stress completed successfully.
Thanks,
Jaehoon.
> ---
> Cc: Halil Pasic <pasic@linux.ibm.com>
> Cc: Matthew Rosato <mjrosato@linux.ibm.com>
> Cc: Jaehoon Kim <jhkim@linux.ibm.com>
> ---
> arch/s390/Kconfig | 1 +
> arch/s390/mm/init.c | 14 ++++++++++++++
> 2 files changed, 15 insertions(+)
>
> diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
> index ecbcbb781e40..9b5e6029e043 100644
> --- a/arch/s390/Kconfig
> +++ b/arch/s390/Kconfig
> @@ -87,6 +87,7 @@ config S390
> select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
> select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
> select ARCH_HAS_CC_CAN_LINK
> + select ARCH_HAS_CC_PLATFORM
> select ARCH_HAS_CPU_FINALIZE_INIT
> select ARCH_HAS_CURRENT_STACK_POINTER
> select ARCH_HAS_DEBUG_VIRTUAL
> diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
> index 1f72efc2a579..ad3c6d92b801 100644
> --- a/arch/s390/mm/init.c
> +++ b/arch/s390/mm/init.c
> @@ -50,6 +50,7 @@
> #include <linux/virtio_anchor.h>
> #include <linux/virtio_config.h>
> #include <linux/execmem.h>
> +#include <linux/cc_platform.h>
>
> pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".bss..swapper_pg_dir");
> pgd_t invalid_pg_dir[PTRS_PER_PGD] __section(".bss..invalid_pg_dir");
> @@ -140,6 +141,19 @@ bool force_dma_unencrypted(struct device *dev)
> return is_prot_virt_guest();
> }
>
> +
> +bool cc_platform_has(enum cc_attr attr)
> +{
> + switch (attr) {
> + case CC_ATTR_MEM_ENCRYPT:
> + return is_prot_virt_guest();
> +
> + default:
> + return false;
> + }
> +}
> +EXPORT_SYMBOL_GPL(cc_platform_has);
> +
> /* protected virtualization */
> static void __init pv_init(void)
> {
^ permalink raw reply
* Re: [PATCH v4] powerpc/pseries/Kconfig: Enable CONFIG_VPA_PMU to be used with KVM
From: Ritesh Harjani @ 2026-06-06 3:07 UTC (permalink / raw)
To: Gautam Menghani, maddy, mpe, npiggin, chleroy
Cc: Gautam Menghani, linuxppc-dev, linux-kernel, harshpb, stable,
Sean Christopherson
In-Reply-To: <20260602121706.8423-1-gautam@linux.ibm.com>
Gautam Menghani <gautam@linux.ibm.com> writes:
> Currently, CONFIG_VPA_PMU is not enabled by default, and consequently
> cannot be used for KVM guests at all, unless explicitly enabled on
> host kernel.
>
> Mark CONFIG_VPA_PMU as "default m" to ensure it is available when KVM is
> being used.
>
> Fixes: 176cda0619b6c ("powerpc/perf: Add perf interface to expose vpa counters")
Not really a fix per-se. So we need not add this fixes tag.
> Cc: stable@vger.kernel.org # v6.13+
I think the stable tag like above is sufficient for stable tree
maintainers to pick this up.
-ritesh
^ permalink raw reply
* Re: [PATCH 06/10] dmaengine: fsldma: convert channel allocation to devm_kzalloc
From: Frank Li @ 2026-06-05 22:45 UTC (permalink / raw)
To: Rosen Penev
Cc: dmaengine, Vinod Koul, Frank Li, Zhang Wei, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, open list,
open list:FREESCALE DMA DRIVER,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260605220134.43295-7-rosenp@gmail.com>
On Fri, Jun 05, 2026 at 03:01:30PM -0700, Rosen Penev wrote:
>
> Convert fsl_dma_chan_probe from kzalloc_obj to devm_kzalloc, tying
> the channel lifetime to the parent DMA device. This removes the
Nit: Remove kfree(chan) in ..
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> need for kfree(chan) in both the probe error path and the remove
> function.
>
> Assisted-by: opencode:big-pickle
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/dma/fsldma.c | 12 +++---------
> 1 file changed, 3 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> index 2a6a247761a4..ee6e595c2972 100644
> --- a/drivers/dma/fsldma.c
> +++ b/drivers/dma/fsldma.c
> @@ -1111,11 +1111,9 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
> int err;
>
> /* alloc channel */
> - chan = kzalloc_obj(*chan);
> - if (!chan) {
> - err = -ENOMEM;
> - goto out_return;
> - }
> + chan = devm_kzalloc(fdev->dev, sizeof(*chan), GFP_KERNEL);
> + if (!chan)
> + return -ENOMEM;
>
> /* ioremap registers for use */
> chan->regs = of_iomap(node, 0);
> @@ -1197,9 +1195,6 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
>
> out_iounmap_regs:
> iounmap(chan->regs);
> -out_free_chan:
> - kfree(chan);
> -out_return:
> return err;
> }
>
> @@ -1208,7 +1203,6 @@ static void fsl_dma_chan_remove(struct fsldma_chan *chan)
> tasklet_kill(&chan->tasklet);
> list_del(&chan->common.device_node);
> iounmap(chan->regs);
> - kfree(chan);
> }
>
> static int fsldma_of_probe(struct platform_device *op)
> --
> 2.54.0
>
^ permalink raw reply
* [PATCH] perf data convert json: Fix addr_location leak on time-filtered samples
From: Tanushree Shah @ 2026-06-06 12:15 UTC (permalink / raw)
To: acme, jolsa, adrian.hunter, vmolnaro, mpetlan, tmricht, maddy,
irogers, namhyung
Cc: linux-perf-users, linuxppc-dev, atrajeev, hbathini, Tejas.Manhas1,
Tanushree.Shah, Shivani.Nittor, Tanushree Shah
When samples are skipped due to time filtering in process_sample_event(),
the early return path bypasses addr_location__exit(), causing memory leaks
of thread, map, and maps references acquired by machine__resolve().
These references must be released through addr_location__exit() before
returning.
Fixes: 8e746e95c3e4 ("perf data: Allow filtering conversion by time range")
Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
---
tools/perf/util/data-convert-json.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/perf/util/data-convert-json.c b/tools/perf/util/data-convert-json.c
index d526c91312ed..6a8d00c80394 100644
--- a/tools/perf/util/data-convert-json.c
+++ b/tools/perf/util/data-convert-json.c
@@ -177,6 +177,7 @@ static int process_sample_event(const struct perf_tool *tool,
if (perf_time__ranges_skip_sample(c->ptime_range, c->range_num, sample->time)) {
++c->skipped;
+ addr_location__exit(&al);
return 0;
}
--
2.47.3
^ permalink raw reply related
* [RFC PATCH 0/1] powerpc/fadump: move crash memory reservation to middle of RAM
From: Sourabh Jain @ 2026-06-06 15:17 UTC (permalink / raw)
To: linuxppc-dev, maddy, mpe
Cc: npiggin, chleroy, ritesh.list, shivangu, hbathini, mahesh,
adityag, venkat88, sourabhjain, avnish, sayalip
The current fadump crash memory reservation policy places the crash
memory area at an offset derived from the crashkernel reservation
size. For example, with crashkernel=768M, the crash memory area starts
at 768M physical address.
This layout assumes that bootloader memory usage remains below the
crash memory reservation area during the reboot flow after a kernel
crash.
With fadump enabled, a crashed system reboots and firmware preserves
the crashed kernel memory while passing special device tree properties
to the next kernel. Before the capture kernel boots, GRUB is invoked
again as part of the normal reboot sequence.
Currently GRUB limits its memory usage below 768M, which aligns with
the minimum crashkernel reservation supported by fadump. However, if
GRUB increases this limit in future, it can potentially overwrite the
preserved crash memory and corrupt the dump before the capture kernel
boots.
To avoid depending on bootloader memory limits, place the fadump crash
memory reservation area in the middle of system RAM instead of deriving
its base from the crashkernel reservation size.
Since we have changed the fadump crash memory reservation base address
policy in the past, I am sending this patch as RFC to discuss any
potential side effects before moving the fadump base address to the
middle of system RAM again.
The following commits are related to the previous reservation policy
changes:
Commit 140777a3d8df ("powerpc/fadump: consider reserved ranges while
reserving memory")
Commit f6e6bedb7731 ("powerpc/fadump: Reserve memory at an offset
closer to bottom of RAM")
Sourabh Jain (1):
powerpc/fadump: move crash memory reservation to middle of RAM
arch/powerpc/kernel/fadump.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--
2.52.0
^ permalink raw reply
* [RFC PATCH 1/1] powerpc/fadump: move crash memory reservation to middle of RAM
From: Sourabh Jain @ 2026-06-06 15:17 UTC (permalink / raw)
To: linuxppc-dev, maddy, mpe
Cc: npiggin, chleroy, ritesh.list, shivangu, hbathini, mahesh,
adityag, venkat88, sourabhjain, avnish, sayalip
In-Reply-To: <20260606151739.1720246-1-sourabhjain@linux.ibm.com>
Currently, the fadump crash memory reservation base is derived from
the crashkernel reservation size. For example, with crashkernel=768M,
the crash memory area is preferably placed at 768M physical address.
If a suitable reservation area is not available due to memory holes or
reserved ranges, the base address is adjusted accordingly.
When a kernel crashes with fadump enabled, the system performs a reboot
and the next kernel boots with special device tree properties added by
firmware to indicate an active dump. During this reboot flow, GRUB is
invoked again before the capture kernel boots.
To preserve the crashed kernel memory, GRUB operation must stay below
the fadump crash memory reservation area. Currently this works because
fadump requires a minimum crashkernel reservation of 768M, which ensures
that the fadump memory reservation base address is at least 768M.
However, if GRUB increases its memory access range in future, it may
overwrite the preserved crash memory before the capture kernel boots,
resulting in dump corruption.
Avoid this dependency by moving the fadump crash memory reservation
base to the middle of system RAM instead of deriving it from the
crashkernel reservation size.
Signed-off-by: Sourabh Jain <sourabhjain@linux.ibm.com>
---
arch/powerpc/kernel/fadump.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 501d43bf18f3..1b4a330b7de0 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -586,7 +586,11 @@ int __init fadump_reserve_mem(void)
else
mem_boundary = memblock_end_of_DRAM();
- base = fw_dump.boot_mem_top;
+ if (fw_dump.dump_active)
+ base = fw_dump.boot_mem_top;
+ else
+ base = mem_boundary / 2;
+
size = get_fadump_area_size();
fw_dump.reserve_dump_area_size = size;
if (fw_dump.dump_active) {
--
2.52.0
^ permalink raw reply related
* Re: [PATCH] perf data convert json: Fix addr_location leak on time-filtered samples
From: Ian Rogers @ 2026-06-06 15:47 UTC (permalink / raw)
To: Tanushree Shah
Cc: acme, jolsa, adrian.hunter, vmolnaro, mpetlan, tmricht, maddy,
namhyung, linux-perf-users, linuxppc-dev, atrajeev, hbathini,
Tejas.Manhas1, Tanushree.Shah, Shivani.Nittor
In-Reply-To: <20260606121528.406919-2-tshah@linux.ibm.com>
On Sat, Jun 6, 2026 at 5:20 AM Tanushree Shah <tshah@linux.ibm.com> wrote:
>
> When samples are skipped due to time filtering in process_sample_event(),
> the early return path bypasses addr_location__exit(), causing memory leaks
> of thread, map, and maps references acquired by machine__resolve().
>
> These references must be released through addr_location__exit() before
> returning.
>
> Fixes: 8e746e95c3e4 ("perf data: Allow filtering conversion by time range")
> Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Thanks,
Ian
> ---
> tools/perf/util/data-convert-json.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/tools/perf/util/data-convert-json.c b/tools/perf/util/data-convert-json.c
> index d526c91312ed..6a8d00c80394 100644
> --- a/tools/perf/util/data-convert-json.c
> +++ b/tools/perf/util/data-convert-json.c
> @@ -177,6 +177,7 @@ static int process_sample_event(const struct perf_tool *tool,
>
> if (perf_time__ranges_skip_sample(c->ptime_range, c->range_num, sample->time)) {
> ++c->skipped;
> + addr_location__exit(&al);
> return 0;
> }
>
> --
> 2.47.3
>
^ permalink raw reply
* Re: [v2 1/2] KVM: LoongArch: Validate irqchip index in irqfd routing
From: Huacai Chen @ 2026-06-07 4:41 UTC (permalink / raw)
To: Yanfei Xu
Cc: harshpb, zhaotianrui, maobibo, maddy, npiggin, sashiko-reviews,
seanjc, pbonzini, kvm, stable, loongarch, linuxppc-dev,
caixiangfeng, fangying.tommy, isyanfei.xu, Sashiko
In-Reply-To: <20260531135326.2238555-2-yanfei.xu@bytedance.com>
Applied, thanks.
Huacai
On Sun, May 31, 2026 at 9:54 PM Yanfei Xu <yanfei.xu@bytedance.com> wrote:
>
> Sashiko reported that the irqchip index is not validated for LoongArch.
> Add validation and reject out-of-range irqchip indexes to avoid indexing
> past the routing table's chip array.
>
> Fixes: 1928254c5ccb ("LoongArch: KVM: Add irqfd support")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/kvm/20260525051714.485D51F000E9@smtp.kernel.org/
> Reviewed-by: Bibo Mao <maobibo@loongson.cn>
> Signed-off-by: Yanfei Xu <yanfei.xu@bytedance.com>
> ---
> arch/loongarch/kvm/irqfd.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/arch/loongarch/kvm/irqfd.c b/arch/loongarch/kvm/irqfd.c
> index f4f953b22419..40ed1081c4b6 100644
> --- a/arch/loongarch/kvm/irqfd.c
> +++ b/arch/loongarch/kvm/irqfd.c
> @@ -51,7 +51,8 @@ int kvm_set_routing_entry(struct kvm *kvm,
> e->irqchip.irqchip = ue->u.irqchip.irqchip;
> e->irqchip.pin = ue->u.irqchip.pin;
>
> - if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
> + if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS ||
> + e->irqchip.irqchip >= KVM_NR_IRQCHIPS)
> return -EINVAL;
>
> return 0;
> --
> 2.20.1
>
^ permalink raw reply
* Re: [PATCH v2 1/5] powerpc/rtas: Handle special return format for RTAS_FN_IBM_OPEN_ERRINJCT
From: Sourabh Jain @ 2026-06-07 11:19 UTC (permalink / raw)
To: Narayana Murty N, mahesh, maddy, mpe, christophe.leroy, gregkh,
oohall, npiggin
Cc: linuxppc-dev, linux-kernel, tyreld, vaibhav, sbhat, ganeshgr,
haren, thuth
In-Reply-To: <20260527072433.94510-2-nnmlinux@linux.ibm.com>
On 27/05/26 12:54, Narayana Murty N wrote:
> RTAS_FN_IBM_OPEN_ERRINJCT returns results in special format:
> rets[0] = session token (output)
> rets[1] = status code
> rets[2..] = additional outputs (if any)
>
> Unlike standard RTAS calls where:
> rets[0] = status code
> rets[1..] = outputs
>
> This patch adds special handling for OPEN_ERRINJCT to:
> 1. Check correct status position (rets[1]) for __fetch_rtas_last_error()
You can consider fixing the same for the RTAS syscall.
> 2. Copy all rets[0..nret-1] to outputs[] (including token at rets[0])
> 3. Return status from rets[1] instead of rets[0]
>
> Reference: OpenPOWER PAPR documentation
> https://files.openpower.foundation/s/XFgfMaqLMD5Bcm8
> Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
> ---
> arch/powerpc/kernel/rtas.c | 47 ++++++++++++++++++++++++++++++++------
> 1 file changed, 40 insertions(+), 7 deletions(-)
>
> diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
> index 8d81c1e7a8db..a2dd94eed9d0 100644
> --- a/arch/powerpc/kernel/rtas.c
> +++ b/arch/powerpc/kernel/rtas.c
> @@ -1183,7 +1183,7 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
> unsigned long flags;
> struct rtas_args *args;
> char *buff_copy = NULL;
> - int ret;
> + int ret = 0;
>
> if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE)
> return -1;
> @@ -1213,15 +1213,48 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
> va_rtas_call_unlocked(args, token, nargs, nret, list);
> va_end(list);
>
> + /*
> + * Special handling for RTAS_FN_IBM_OPEN_ERRINJCT:
> + * Per PAPR, ibm,open-errinjct has a unique return format:
> + * rets[0] = injection session token (output parameter)
> + * rets[1] = status code
> + *
> + * This differs from standard RTAS calls which return:
> + * rets[0] = status code
> + * rets[1..] = output parameters
> + *
> + * We must extract status from rets[1] (not rets[0]) to correctly
> + * detect errors and trigger __fetch_rtas_last_error() when status == -1.
> + */
> /* A -1 return code indicates that the last command couldn't
> - be completed due to a hardware error. */
The above comment should be moved to next if block, if (ret == -1).
> - if (be32_to_cpu(args->rets[0]) == -1)
> + * be completed due to a hardware error.
> + */
> + if (token == rtas_function_token(RTAS_FN_IBM_OPEN_ERRINJCT) && nret > 1)
> + ret = be32_to_cpu(args->rets[1]);
> + else if (nret > 0)
> + ret = be32_to_cpu(args->rets[0]);
> +
> + if (ret == -1)
> buff_copy = __fetch_rtas_last_error(NULL);
>
> - if (nret > 1 && outputs != NULL)
> - for (i = 0; i < nret-1; ++i)
> - outputs[i] = be32_to_cpu(args->rets[i + 1]);
> - ret = (nret > 0) ? be32_to_cpu(args->rets[0]) : 0;
> + /* Copy all return values to caller's outputs buffer if provided */
> + if (nret > 1 && outputs != NULL) {
> + if (token == rtas_function_token(RTAS_FN_IBM_OPEN_ERRINJCT)) {
> + /* Special case: rets[0]=token, rets[1]=status, rets[2..]=outputs */
> + for (i = 0; i < nret; ++i)
> + outputs[i] = be32_to_cpu(args->rets[i]);
> + } else {
> + /* Normal case: rets[0]=status, rets[1..]=outputs */
> + for (i = 0; i < nret - 1; ++i)
> + outputs[i] = be32_to_cpu(args->rets[i + 1]);
I am surprised that status is never copied to the output buffer even
though it is part
of the output as per PAPR. But status is copied for ibm,open-errinjct,
which is okay.
> + }
> + } else {
> + /* Either no outputs to copy (nret <= 1) or caller
> + * didn't provide output buffer ensure ret contains
> + * the status code for standard RTAS calls.
> + */
> + ret = (nret > 0) ? be32_to_cpu(args->rets[0]) : 0;
What is the need to find ret again? Isn't it already done above?
> + }
>
> lockdep_unpin_lock(&rtas_lock, cookie);
> raw_spin_unlock_irqrestore(&rtas_lock, flags);
^ permalink raw reply
* Re: [PATCH v2 3/5] powerpc/pseries: Add RTAS error injection validation helpers
From: Sourabh Jain @ 2026-06-07 12:17 UTC (permalink / raw)
To: Narayana Murty N, mahesh, maddy, mpe, christophe.leroy, gregkh,
oohall, npiggin
Cc: linuxppc-dev, linux-kernel, tyreld, vaibhav, sbhat, ganeshgr,
haren, thuth
In-Reply-To: <20260527072433.94510-4-nnmlinux@linux.ibm.com>
On 27/05/26 12:54, Narayana Murty N wrote:
> Add comprehensive validation helpers for RTAS error injection parameters:
> - validate_addr_mask_in_pe(): BAR range validation
> - validate_err_type(): Token range check
> - Type-specific validators (special-event, corrupted-page, ioa-bus-error)
>
> Reported-by: kernel test robot <lkp@intel.com>
> Closes: https://lore.kernel.org/oe-kbuild-all/202512101130.EYUo0oZx-lkp@intel.com/
>
> Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
> ---
> arch/powerpc/platforms/pseries/eeh_pseries.c | 261 +++++++++++++++++++
> 1 file changed, 261 insertions(+)
>
> diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
> index b12ef382fec7..d6f2e0d43b89 100644
> --- a/arch/powerpc/platforms/pseries/eeh_pseries.c
> +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
> @@ -33,6 +33,10 @@
> #include <asm/ppc-pci.h>
> #include <asm/rtas.h>
>
> +#ifndef pr_fmt
> +#define pr_fmt(fmt) "EEH: " fmt
Why this is under ifndef?
> +#endif
> +
> /* RTAS tokens */
> static int ibm_set_eeh_option;
> static int ibm_set_slot_reset;
> @@ -786,6 +790,263 @@ static int pseries_notify_resume(struct eeh_dev *edev)
> }
> #endif
>
> +/**
> + * validate_addr_mask_in_pe - Validate that an addr+mask fall within PE's BARs
> + * @pe: EEH PE containing one or more PCI devices
> + * @addr: Address to validate
> + * @mask: Address mask to validate
> + *
> + * Checks that @addr is mapped into a BAR/MMIO region of any device belonging
> + * to the PE. If @mask is non-zero, ensures it is consistent with @addr.
> + *
> + * Return: 0 if valid, RTAS_INVALID_PARAMETER on failure.
> + */
> +
> +static int validate_addr_mask_in_pe(struct eeh_pe *pe, unsigned long addr,
> + unsigned long mask)
> +{
> + struct eeh_dev *edev, *tmp;
> + struct pci_dev *pdev;
> + int bar;
> + resource_size_t bar_start, bar_len;
> + bool valid = false;
> +
> + /* nothing to validate */
> + if (addr == 0 && mask == 0)
> + return 0;
> +
> + eeh_pe_for_each_dev(pe, edev, tmp) {
> + pdev = eeh_dev_to_pci_dev(edev);
> + if (!pdev)
> + continue;
> +
> + for (bar = 0; bar < PCI_NUM_RESOURCES; bar++) {
> + bar_start = pci_resource_start(pdev, bar);
> + bar_len = pci_resource_len(pdev, bar);
> +
> + if (!bar_len)
> + continue;
> +
> + if (addr >= bar_start && addr < (bar_start + bar_len)) {
> + /* ensure mask makes sense for the addr value */
> + if ((addr & mask) != addr) {
> + pr_err("Mask 0x%lx invalid for addr 0x%lx in BAR[%d] range 0x%llx-0x%llx\n",
> + mask, addr, bar,
> + (unsigned long long)bar_start,
> + (unsigned long long)(bar_start + bar_len));
> + return RTAS_INVALID_PARAMETER;
> + }
> +
> + pr_debug("addr=0x%lx with mask=0x%lx validated in BAR[%d] of %s\n",
> + addr, mask, bar, pci_name(pdev));
> + valid = true;
> + }
> + }
> + }
> +
> + if (!valid) {
> + pr_err("addr=0x%lx not valid within any BAR of any device in PE\n",
> + addr);
> + return RTAS_INVALID_PARAMETER;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * validate_err_type - Basic sanity check for RTAS error type
> + * @type: RTAS error type
> + *
> + * Ensures that the error type is within the valid RTAS error type range.
> + *
> + * Return: true if valid, false otherwise.
> + */
> +
> +static bool validate_err_type(int type)
> +{
> + if (type < RTAS_ERR_TYPE_FATAL ||
> + type > RTAS_ERR_TYPE_UPSTREAM_IO_ERROR)
> + return false;
> +
> + return true;
> +}
How about defining this and the function below as inline?
> +
> +/**
> + * validate_special_event - Validate parameters for special-event injection
> + * @addr: Address parameter (should be zero)
> + * @mask: Mask parameter (should be zero)
> + *
> + * Special-event error injection should not take addr/mask. Rejects if either
> + * is set.
> + *
> + * Return: 0 if valid, RTAS_INVALID_PARAMETER otherwise.
> + */
> +
> +static int validate_special_event(unsigned long addr, unsigned long mask)
> +{
> + if (addr || mask) {
> + pr_err("Special-event should not specify addr/mask\n");
> + return RTAS_INVALID_PARAMETER;
> + }
> + return 0;
> +}
> +
> +/**
> + * validate_corrupted_page - Validate parameters for corrupted-page injection
> + * @pe: EEH PE (__maybe_unused)
> + * @addr: Physical page address (required)
> + * @mask: Address mask (ignored if non-zero)
> + *
> + * Ensures a valid non-zero page address is provided. Warns if mask is set.
> + *
> + * Return: 0 if valid, RTAS_INVALID_PARAMETER otherwise.
> + */
> +
> +static int validate_corrupted_page(struct eeh_pe *pe __maybe_unused,
> + unsigned long addr, unsigned long mask)
pe is not used in this function and it is removed in the next patch. Why
don't
we define this function properly in this patch itself.
> +{
> + if (!addr) {
> + pr_err("corrupted-page requires non-zero addr\n");
> + return RTAS_INVALID_PARAMETER;
> + }
> + /* Mask not meaningful for corrupted-page */
If it is not meaningful why can't we ignore it?
> + if (mask)
> + pr_warn("corrupted-page ignoring mask=0x%lx\n", mask);
> +
> + return 0;
> +}
> +
> +/**
> + * validate_ioa_bus_error - Validate parameters for IOA bus error injection
> + * @pe: EEH PE whose BARs are validated against
> + * @addr: Address parameter (optional)
> + * @mask: Mask parameter (optional)
> + *
> + * For IOA bus error injections, @addr and @mask are optional. If present,
> + * they must map into the PE's MMIO/CFG space.
> + *
> + * Return: 0 if valid or addr/mask absent, RTAS_INVALID_PARAMETER otherwise.
> + */
> +
> +static int validate_ioa_bus_error(struct eeh_pe *pe,
> + unsigned long addr, unsigned long mask)
> +{
> + /* Must map into BAR/MMIO/CFG space of PE */
> + return validate_addr_mask_in_pe(pe, addr, mask);
What is the benefit of adding a static helper function that just calls
another
static helper function in the same file?
> +}
> +
> +
> +/**
> + * prepare_errinjct_buffer - Prepare RTAS error injection work buffer
> + * @pe: EEH PE for the target device(s)
> + * @type: RTAS error type
> + * @func: Error function selector (semantics vary by type)
> + * @addr: Address argument (type-dependent)
> + * @mask: Mask argument (type-dependent)
Isn't the caller of this helper expected to hold rtas_errinjct_buf_lock?
If that is
the case, let's document it.
> + *
> + * Clears the global error injection work buffer and populates it based on
> + * the error type and parameters provided. Performs inline validation of the
> + * arguments for each supported error type.
> + *
> + * Return: 0 on success, or RTAS_INVALID_PARAMETER / -EINVAL on failure.
> + */
> +
> +static int prepare_errinjct_buffer(struct eeh_pe *pe, int type, int func,
> + unsigned long addr, unsigned long mask)
> +{
> + __be64 *buf64;
> + __be32 *buf32;
> +
> + memset(rtas_errinjct_buf, 0, RTAS_ERRINJCT_BUF_SIZE);
> + buf64 = (__be64 *)rtas_errinjct_buf;
> + buf32 = (__be32 *)rtas_errinjct_buf;
> +
> + switch (type) {
> + case RTAS_ERR_TYPE_RECOVERED_SPECIAL_EVENT:
> + /* func must be 1 = non-persistent or 2 = persistent */
> + if (func < 1 || func > 2)
> + return RTAS_INVALID_PARAMETER;
> +
> + if (validate_special_event(addr, mask))
> + return RTAS_INVALID_PARAMETER;
> +
> + buf32[0] = cpu_to_be32(func);
> + break;
> +
> + case RTAS_ERR_TYPE_CORRUPTED_PAGE:
> + /* addr required: physical page address */
> + if (addr == 0)
> + return RTAS_INVALID_PARAMETER;
> +
> + if (validate_corrupted_page(pe, addr, mask))
> + return RTAS_INVALID_PARAMETER;
> +
> + buf32[0] = cpu_to_be32(upper_32_bits(addr));
> + buf32[1] = cpu_to_be32(lower_32_bits(addr));
> + break;
> +
> + case RTAS_ERR_TYPE_IOA_BUS_ERROR:
> + /* 32-bit IOA bus error: addr/mask optional */
> + if (func < EEH_ERR_FUNC_LD_MEM_ADDR || func > EEH_ERR_FUNC_MAX)
> + return RTAS_INVALID_PARAMETER;
> +
> + if (addr || mask) {
> + if (validate_ioa_bus_error(pe, addr, mask))
> + return RTAS_INVALID_PARAMETER;
> + }
> +
> + buf32[0] = cpu_to_be32((u32)addr);
> + buf32[1] = cpu_to_be32((u32)mask);
> + buf32[2] = cpu_to_be32(pe->addr);
> + buf32[3] = cpu_to_be32(BUID_HI(pe->phb->buid));
> + buf32[4] = cpu_to_be32(BUID_LO(pe->phb->buid));
> + buf32[5] = cpu_to_be32(func);
> + break;
> +
> + case RTAS_ERR_TYPE_IOA_BUS_ERROR_64:
> + /* 64-bit IOA bus error: addr/mask optional */
> + if (func < EEH_ERR_FUNC_MIN || func > EEH_ERR_FUNC_MAX)
> + return RTAS_INVALID_PARAMETER;
> +
> + if (addr || mask) {
> + if (validate_ioa_bus_error(pe, addr, mask))
> + return RTAS_INVALID_PARAMETER;
> + }
> +
> + buf64[0] = cpu_to_be64(addr);
> + buf64[1] = cpu_to_be64(mask);
> + buf32[4] = cpu_to_be32(pe->addr);
> + buf32[5] = cpu_to_be32(BUID_HI(pe->phb->buid));
> + buf32[6] = cpu_to_be32(BUID_LO(pe->phb->buid));
> + buf32[7] = cpu_to_be32(func);
> + break;
> +
> + case RTAS_ERR_TYPE_CORRUPTED_DCACHE_START:
> + case RTAS_ERR_TYPE_CORRUPTED_DCACHE_END:
> + case RTAS_ERR_TYPE_CORRUPTED_ICACHE_START:
> + case RTAS_ERR_TYPE_CORRUPTED_ICACHE_END:
> + /* addr/mask optional, no strict validation */
> + buf32[0] = cpu_to_be32(addr);
> + buf32[1] = cpu_to_be32(mask);
> + break;
> +
> + case RTAS_ERR_TYPE_CORRUPTED_TLB_START:
> + case RTAS_ERR_TYPE_CORRUPTED_TLB_END:
> + /* only addr field relevant */
> + buf32[0] = cpu_to_be32(addr);
> + break;
> +
> + default:
> + pr_err("Unsupported error type 0x%x\n", type);
> + return -EINVAL;
> + }
> +
> + pr_debug("RTAS: errinjct buffer prepared: type=%d func=%d addr=0x%lx mask=0x%lx\n",
> + type, func, addr, mask);
> +
> + return 0;
> +}
> +
> /**
> * pseries_eeh_err_inject - Inject specified error to the indicated PE
> * @pe: the indicated PE
^ permalink raw reply
* Re: [PATCH v2 4/5] powerpc/pseries: Implement RTAS error injection via pseries_eeh_err_inject
From: Sourabh Jain @ 2026-06-07 13:35 UTC (permalink / raw)
To: Narayana Murty N, mahesh, maddy, mpe, christophe.leroy, gregkh,
oohall, npiggin
Cc: linuxppc-dev, linux-kernel, tyreld, vaibhav, sbhat, ganeshgr,
haren, thuth
In-Reply-To: <20260527072433.94510-5-nnmlinux@linux.ibm.com>
On 27/05/26 12:54, Narayana Murty N wrote:
> Replace legacy MMIO error injection with full PAPR-compliant RTAS error
> injection supporting 14+ error types via
> - ibm,open-errinjct
> - ibm,errinjct
> - ibm,close-errinjct.
>
> Key features:
> - Complete open-session-inject-close cycle management
> - Special handling for ibm,open-errinjct output format (token,status)
> - Comprehensive buffer preparation per PAPR layouts
> - All pr_* logging uses pr_fmt("EEH: ") prefix
>
> Tested with corresponding QEMU patches:
> https://lore.kernel.org/all/20251029150618.186803-1-nnmlinux@linux.ibm.com/
>
> Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
> ---
> arch/powerpc/platforms/pseries/eeh_pseries.c | 168 ++++++++++++++++---
> 1 file changed, 147 insertions(+), 21 deletions(-)
>
> diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
> index d6f2e0d43b89..6af2a153ec25 100644
> --- a/arch/powerpc/platforms/pseries/eeh_pseries.c
> +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
> @@ -902,8 +902,7 @@ static int validate_special_event(unsigned long addr, unsigned long mask)
> * Return: 0 if valid, RTAS_INVALID_PARAMETER otherwise.
> */
>
> -static int validate_corrupted_page(struct eeh_pe *pe __maybe_unused,
> - unsigned long addr, unsigned long mask)
> +static int validate_corrupted_page(unsigned long addr, unsigned long mask)
> {
> if (!addr) {
> pr_err("corrupted-page requires non-zero addr\n");
> @@ -978,7 +977,7 @@ static int prepare_errinjct_buffer(struct eeh_pe *pe, int type, int func,
> if (addr == 0)
> return RTAS_INVALID_PARAMETER;
>
> - if (validate_corrupted_page(pe, addr, mask))
> + if (validate_corrupted_page(addr, mask))
> return RTAS_INVALID_PARAMETER;
>
> buf32[0] = cpu_to_be32(upper_32_bits(addr));
> @@ -1047,6 +1046,97 @@ static int prepare_errinjct_buffer(struct eeh_pe *pe, int type, int func,
> return 0;
> }
>
> +/**
> + * rtas_open_errinjct_session - Open an RTAS error injection session
> + *
> + * Opens a session with the RTAS ibm,open-errinjct service.
> + *
> + * Return: Positive session token on success, negative error code on failure.
session token can't be 0, is it?
> + */
> +static int rtas_open_errinjct_session(void)
> +{
> + int open_token, args[2] = {0};
> + int rc, status, session_token = -1;
> +
> + open_token = rtas_function_token(RTAS_FN_IBM_OPEN_ERRINJCT);
> + if (open_token == RTAS_UNKNOWN_SERVICE) {
> + pr_err("RTAS: ibm,open-errinjct not available\n");
> + return RTAS_UNKNOWN_SERVICE;
> + }
> +
> + /* Call open; original code treated rtas_call return as session token */
> + rc = rtas_call(open_token, 0, 2, args);
> + status = args[1];
rc and status is same, isn't it? That makes the status variable redundant.
> + if (status != 0) {
> + pr_err("RTAS: open-errinjct failed: status=%d args[1]=%d rc=%d\n",
> + status, args[1], rc);
> + return status ? status : -EIO;
> + }
Not planning to handle extend delay by RTAS, return code 9900...9905?
> +
> + session_token = args[0];
> + pr_info("Opened injection session: token=%d\n", session_token);
> + return session_token;
> +}
> +
> +/**
> + * rtas_close_errinjct_session - Close an RTAS error injection session
> + * @session_token: Session token returned from open
> + *
> + * Attempts to close a previously opened error injection session. Best-effort;
> + * logs warnings if close fails or if service is unavailable.
> + */
> +
> +static void rtas_close_errinjct_session(int session_token)
> +{
> + int close_token, args[2] = {0};
> +
> + if (session_token <= 0)
> + return;
I didn't find a section in the PAPR which says token can't be 0.
> +
> + close_token = rtas_function_token(RTAS_FN_IBM_CLOSE_ERRINJCT);
> + if (close_token == RTAS_UNKNOWN_SERVICE) {
> + pr_warn("close-errinjct not available\n");
> + return;
> + }
> +
> + args[0] = session_token;
> + rtas_call(close_token, 1, 1, args);
> + if (args[0])
> + pr_warn("close-errinjct args[0]=%d\n", args[0]);
IIUC rtas_call do not copy status to output buffer. Let's consider
return value
from rtas_call function as status.
Since status is not copied, int arg is enough.
I think we must handle rtas busy delay for errinjct close rtas call?
> +}
> +
> +/**
> + * do_errinjct_call - Invoke the RTAS error injection service
> + * @errinjct_token: RTAS token for ibm,errinjct
> + * @type: RTAS error type
> + * @session_token: RTAS error injection session token
> + *
> + * Issues the RTAS ibm,errinjct call with the prepared work buffer. Logs errors
> + * on failure.
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +
> +static int do_errinjct_call(int errinjct_token, int type, int session_token)
> +{
> + int rc, status;
> +
> + if (errinjct_token == RTAS_UNKNOWN_SERVICE)
> + return -ENODEV;
> +
> + /* errinjct takes: type, session_token, workbuf pointer (3 in), returns status */
> + rc = rtas_call(errinjct_token, 3, 1, &status, type, session_token,
> + rtas_errinjct_buf);
> +
> + if (rc || status != 0) {
> + pr_err("RTAS: errinjct failed: rc=%d, status=%d\n", rc, status);
> + return status ? status : -EIO;
> + }
> +
> + pr_info("RTAS: errinjct ok: rc=%d, status=%d\n", rc, status);
> + return 0;
> +}
> +
> /**
> * pseries_eeh_err_inject - Inject specified error to the indicated PE
> * @pe: the indicated PE
> @@ -1060,30 +1150,66 @@ static int prepare_errinjct_buffer(struct eeh_pe *pe, int type, int func,
> static int pseries_eeh_err_inject(struct eeh_pe *pe, int type, int func,
> unsigned long addr, unsigned long mask)
> {
> - struct eeh_dev *pdev;
> + int rc = 0;
> + int session_token = -1;
> + int errinjct_token;
>
> - /* Check on PCI error type */
> - if (type != EEH_ERR_TYPE_32 && type != EEH_ERR_TYPE_64)
> - return -EINVAL;
> + /* Validate type */
> + if (!validate_err_type(type)) {
> + pr_err("RTAS: invalid error type 0x%x\n", type);
> + return RTAS_INVALID_PARAMETER;
> + }
> + pr_debug("RTAS: error type 0x%x\n", type);
>
> - switch (func) {
> - case EEH_ERR_FUNC_LD_MEM_ADDR:
> - case EEH_ERR_FUNC_LD_MEM_DATA:
> - case EEH_ERR_FUNC_ST_MEM_ADDR:
> - case EEH_ERR_FUNC_ST_MEM_DATA:
> - /* injects a MMIO error for all pdev's belonging to PE */
> - pci_lock_rescan_remove();
> - list_for_each_entry(pdev, &pe->edevs, entry)
> - eeh_pe_inject_mmio_error(pdev->pdev);
> - pci_unlock_rescan_remove();
> - break;
> - default:
> - return -ERANGE;
> + /* For IOA bus errors we must validate err_func and addr/mask in PE.
> + * For other types: if addr/mask present we'll still validate BAR range;
> + * otherwise skip function checks.
> + */
> + if (type == RTAS_ERR_TYPE_IOA_BUS_ERROR ||
> + type == RTAS_ERR_TYPE_IOA_BUS_ERROR_64) {
> + /* Validate that addr/mask fall in the PE's BAR ranges */
> + rc = validate_addr_mask_in_pe(pe, addr, mask);
> + if (rc)
> + return rc;
> + } else if (addr || mask) {
> + /* If caller provided addr/mask for a non-IOA type, do a BAR check too */
> + rc = validate_addr_mask_in_pe(pe, addr, mask);
> + if (rc)
> + return rc;
> }
The above if and else if case has identical code. Why don't we merge them?
>
> - return 0;
> + /* Open RTAS session */
> + session_token = rtas_open_errinjct_session();
> + if (session_token < 0)
session_token 0 is considered valid here. Where as it was considered
invalid in other
function above.
> + return session_token;
> +
> + /* get errinjct token */
> + errinjct_token = rtas_function_token(RTAS_FN_IBM_ERRINJCT);
> + if (errinjct_token == RTAS_UNKNOWN_SERVICE) {
How about checking this before getting the session token?
> + pr_err("RTAS: ibm,errinjct not available\n");
> + rc = -ENODEV;
> + goto out_close;
> + }
> +
> + /* prepare shared buffer while holding lock */
> + spin_lock(&rtas_errinjct_buf_lock);
> + rc = prepare_errinjct_buffer(pe, type, func, addr, mask);
> + if (rc) {
> + spin_unlock(&rtas_errinjct_buf_lock);
> + goto out_close;
> + }
> +
> + /* perform the errinjct RTAS call */
> + rc = do_errinjct_call(errinjct_token, type, session_token);
> + spin_unlock(&rtas_errinjct_buf_lock);
> +
> +out_close:
> + /* always attempt close if we opened a session */
> + rtas_close_errinjct_session(session_token);
> + return rc;
> }
>
> +
This new line seems unnecessary.
> static struct eeh_ops pseries_eeh_ops = {
> .name = "pseries",
> .probe = pseries_eeh_probe,
^ permalink raw reply
* Re: [PATCH v2 5/5] powerpc/powernv: Map EEH error types to OPAL error injection types
From: Sourabh Jain @ 2026-06-07 13:46 UTC (permalink / raw)
To: Narayana Murty N, mahesh, maddy, mpe, christophe.leroy, gregkh,
oohall, npiggin
Cc: linuxppc-dev, linux-kernel, tyreld, vaibhav, sbhat, ganeshgr,
haren, thuth
In-Reply-To: <20260527072433.94510-6-nnmlinux@linux.ibm.com>
With the cover letter, this patch series seems to be about RTAS/pseries.
I am not able to understand why powernv changes are part of this
patch series. Could you please explain why they are included here?
On 27/05/26 12:54, Narayana Murty N wrote:
> Add a mapping layer in pnv_eeh_err_inject() to translate generic EEH
> error types to OPAL-specific error injection types. This decouples the
> VFIO error injection interface from OPAL implementation details.
>
> Map EEH_ERR_TYPE_32 to OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR and
> EEH_ERR_TYPE_64 to OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64. Return -EINVAL
> for unsupported error types.
>
> This provides better abstraction between the generic EEH layer and
> platform-specific implementation.
>
> Signed-off-by: Narayana Murty N <nnmlinux@linux.ibm.com>
> ---
> arch/powerpc/include/uapi/asm/eeh.h | 20 ++++++++++++++++++--
> arch/powerpc/platforms/powernv/eeh-powernv.c | 11 +++++++++--
> 2 files changed, 27 insertions(+), 4 deletions(-)
>
> diff --git a/arch/powerpc/include/uapi/asm/eeh.h b/arch/powerpc/include/uapi/asm/eeh.h
> index 86645cab2827..d88d82796905 100644
> --- a/arch/powerpc/include/uapi/asm/eeh.h
> +++ b/arch/powerpc/include/uapi/asm/eeh.h
> @@ -16,8 +16,24 @@
> #define EEH_PE_STATE_UNAVAIL 5 /* Unavailable */
>
> /* EEH error types and functions */
> -#define EEH_ERR_TYPE_32 0 /* 32-bits error */
> -#define EEH_ERR_TYPE_64 1 /* 64-bits error */
> +#define EEH_ERR_TYPE_FATAL 0x1 /* Fatal error */
> +#define EEH_ERR_TYPE_RECOVERED_RANDOM 0x2 /* Recovered random event */
> +#define EEH_ERR_TYPE_RECOVERED_SPECIAL 0x3 /* Recovered special event */
> +#define EEH_ERR_TYPE_CORRUPTED_PAGE 0x4 /* Corrupted page */
> +#define EEH_ERR_TYPE_CORRUPTED_SLB 0x5 /* Corrupted SLB */
> +#define EEH_ERR_TYPE_TRANSLATOR_FAILURE 0x6 /* Translator failure */
> +#define EEH_ERR_TYPE_32 0x7 /* 32-bit IOA bus error */
> +#define EEH_ERR_TYPE_PLATFORM_SPECIFIC 0x8 /* Platform specific */
> +#define EEH_ERR_TYPE_CORRUPTED_DCACHE_START 0x9 /* Corrupted D-cache start */
> +#define EEH_ERR_TYPE_CORRUPTED_DCACHE_END 0xA /* Corrupted D-cache end */
> +#define EEH_ERR_TYPE_CORRUPTED_ICACHE_START 0xB /* Corrupted I-cache start */
> +#define EEH_ERR_TYPE_CORRUPTED_ICACHE_END 0xC /* Corrupted I-cache end */
> +#define EEH_ERR_TYPE_CORRUPTED_TLB_START 0xD /* Corrupted TLB start */
> +#define EEH_ERR_TYPE_CORRUPTED_TLB_END 0xE /* Corrupted TLB end */
> +#define EEH_ERR_TYPE_64 0xF /* 64-bit IOA bus error */
> +#define EEH_ERR_TYPE_UPSTREAM_IO_ERROR 0x10 /* Upstream IO error */
> +
> +/* EEH supported function types */
> #define EEH_ERR_FUNC_MIN 0
> #define EEH_ERR_FUNC_LD_MEM_ADDR 0 /* Memory load */
> #define EEH_ERR_FUNC_LD_MEM_DATA 1
> diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
> index db3370d1673c..ee156d397e93 100644
> --- a/arch/powerpc/platforms/powernv/eeh-powernv.c
> +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
> @@ -1169,8 +1169,15 @@ static int pnv_eeh_err_inject(struct eeh_pe *pe, int type, int func,
> struct pnv_phb *phb = hose->private_data;
> s64 rc;
>
> - if (type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR &&
> - type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64) {
> + /* Map generic EEH Type to OPAL Type */
> + switch (type) {
> + case EEH_ERR_TYPE_32:
> + type = OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR;
> + break;
> + case EEH_ERR_TYPE_64:
> + type = OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64;
> + break;
> + default:
> pr_warn("%s: Invalid error type %d\n",
> __func__, type);
> return -ERANGE;
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox