[PATCH v2 2/6] dmaengine: sun6i: handle the last partial interrupt bank

Frank Li Frank.li at oss.nxp.com
Fri Oct 23 13:05:03 PDT 2026


On Fri, Oct 23, 2026 at 12:42:36PM -0600, James Hilliard wrote:
> The number of physical channels need not be a multiple of the number
> covered by an interrupt-status register. H3 has twelve channels and
> eight channels per bank. Rounding down the number of banks leaves its
> channels 8 through 11 without completion handling.
>
> Round up the number of banks to visit, and stop processing the last bank
> at num_pchans so unused status bits cannot index past the physical-channel
> array. Use the controller's configured bank size for both limits and
> the physical-channel index.
>
> Fixes: f008db8c00c1 ("dmaengine: sun6i: Add support for Allwinner H3 (sun8i) variant")
> Reported-by: Sashiko <sashiko-bot at kernel.org>
> Closes: https://lore.kernel.org/r/20260706065650.34B131F00A3A@smtp.kernel.org
> Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
> ---
>  drivers/dma/sun6i-dma.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
> index 9d94a37fcf10..0a9645171180 100644
> --- a/drivers/dma/sun6i-dma.c
> +++ b/drivers/dma/sun6i-dma.c
> @@ -587,12 +587,13 @@ static void sun6i_dma_tasklet(struct tasklet_struct *t)
>  static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
>  {
>  	struct sun6i_dma_dev *sdev = dev_id;
> +	u32 channels_per_reg = sdev->cfg->num_channels_per_reg;
>  	struct sun6i_vchan *vchan;
>  	struct sun6i_pchan *pchan;
>  	int i, j, ret = IRQ_NONE;
>  	u32 status;
>
> -	for (i = 0; i < sdev->num_pchans / sdev->cfg->num_channels_per_reg; i++) {
> +	for (i = 0; i < DIV_ROUND_UP(sdev->num_pchans, channels_per_reg); i++) {
>  		status = sun6i_read_irq_stat(sdev, i);
>  		if (!status)
>  			continue;
> @@ -602,8 +603,9 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
>
>  		sun6i_write_irq_stat(sdev, i, status);
>
> -		for (j = 0; (j < sdev->cfg->num_channels_per_reg) && status; j++) {
> -			pchan = sdev->pchans + i * sdev->cfg->num_channels_per_reg + j;
> +		for (j = 0; j < channels_per_reg &&
> +		     i * channels_per_reg + j < sdev->num_pchans && status; j++) {

look like check status first is a little better

		for (j = 0; status &&  j < channels_per_reg &&
			    i * channels_per_reg + j < sdev->num_pchans; j++)

Frank

> +			pchan = sdev->pchans + i * channels_per_reg + j;
>  			vchan = pchan->vchan;
>  			if (vchan && (status & vchan->irq_type)) {
>  				if (vchan->cyclic) {
>
> --
> 2.53.0
>



More information about the linux-arm-kernel mailing list