[PATCHv2] dmaengine: idma64: use kzalloc_flex

From: Rosen Penev

Date: Fri Mar 20 2026 - 23:50:02 EST


Simplifies allocations by using a flexible array member in this struct.

Remove idma64_alloc_desc. It now offers no readability advantages in
this single usage.

Add __counted_by to get extra runtime analysis.

Apply the exact same treatment to struct idma64_dma and devm_kzalloc.

Signed-off-by: Rosen Penev <rosenp@xxxxxxxxx>
---
v2: allocate with GFP_NOWAIT. Was mistakenly removed.
drivers/dma/idma64.c | 30 ++++--------------------------
drivers/dma/idma64.h | 4 ++--
2 files changed, 6 insertions(+), 28 deletions(-)

diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 5fcd1befc92d..d914f50ec309 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -192,23 +192,6 @@ static irqreturn_t idma64_irq(int irq, void *dev)

/* ---------------------------------------------------------------------- */

-static struct idma64_desc *idma64_alloc_desc(unsigned int ndesc)
-{
- struct idma64_desc *desc;
-
- desc = kzalloc_obj(*desc, GFP_NOWAIT);
- if (!desc)
- return NULL;
-
- desc->hw = kzalloc_objs(*desc->hw, ndesc, GFP_NOWAIT);
- if (!desc->hw) {
- kfree(desc);
- return NULL;
- }
-
- return desc;
-}
-
static void idma64_desc_free(struct idma64_chan *idma64c,
struct idma64_desc *desc)
{
@@ -223,7 +206,6 @@ static void idma64_desc_free(struct idma64_chan *idma64c,
} while (i);
}

- kfree(desc->hw);
kfree(desc);
}

@@ -307,10 +289,12 @@ static struct dma_async_tx_descriptor *idma64_prep_slave_sg(
struct scatterlist *sg;
unsigned int i;

- desc = idma64_alloc_desc(sg_len);
+ desc = kzalloc_flex(*desc, hw, sg_len, GFP_NOWAIT);
if (!desc)
return NULL;

+ desc->ndesc = sg_len;
+
for_each_sg(sgl, sg, sg_len, i) {
struct idma64_hw_desc *hw = &desc->hw[i];

@@ -326,7 +310,6 @@ static struct dma_async_tx_descriptor *idma64_prep_slave_sg(
hw->len = sg_dma_len(sg);
}

- desc->ndesc = sg_len;
desc->direction = direction;
desc->status = DMA_IN_PROGRESS;

@@ -541,18 +524,13 @@ static int idma64_probe(struct idma64_chip *chip)
unsigned short i;
int ret;

- idma64 = devm_kzalloc(chip->dev, sizeof(*idma64), GFP_KERNEL);
+ idma64 = devm_kzalloc(chip->dev, struct_size(idma64, chan, nr_chan), GFP_KERNEL);
if (!idma64)
return -ENOMEM;

idma64->regs = chip->regs;
chip->idma64 = idma64;

- idma64->chan = devm_kcalloc(chip->dev, nr_chan, sizeof(*idma64->chan),
- GFP_KERNEL);
- if (!idma64->chan)
- return -ENOMEM;
-
idma64->all_chan_mask = (1 << nr_chan) - 1;

/* Turn off iDMA controller */
diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h
index d013b54356aa..1a67dbb24db5 100644
--- a/drivers/dma/idma64.h
+++ b/drivers/dma/idma64.h
@@ -113,10 +113,10 @@ struct idma64_hw_desc {
struct idma64_desc {
struct virt_dma_desc vdesc;
enum dma_transfer_direction direction;
- struct idma64_hw_desc *hw;
unsigned int ndesc;
size_t length;
enum dma_status status;
+ struct idma64_hw_desc hw[] __counted_by(ndesc);
};

static inline struct idma64_desc *to_idma64_desc(struct virt_dma_desc *vdesc)
@@ -187,7 +187,7 @@ struct idma64 {

/* channels */
unsigned short all_chan_mask;
- struct idma64_chan *chan;
+ struct idma64_chan chan[];
};

static inline struct idma64 *to_idma64(struct dma_device *ddev)
--
2.53.0