From bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 14 Feb 2025 02:17:10 +0000 Subject: [PATCH] 不编译test --- kernel/drivers/dma/bcm2835-dma.c | 148 ++++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 122 insertions(+), 26 deletions(-) diff --git a/kernel/drivers/dma/bcm2835-dma.c b/kernel/drivers/dma/bcm2835-dma.c index 630dfbb..6161f76 100644 --- a/kernel/drivers/dma/bcm2835-dma.c +++ b/kernel/drivers/dma/bcm2835-dma.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/io.h> #include <linux/spinlock.h> +#include <linux/irqstage.h> #include <linux/of.h> #include <linux/of_dma.h> @@ -435,10 +436,20 @@ writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS); } +static inline void bcm2835_dma_enable_channel(struct bcm2835_chan *c) +{ + writel(c->desc->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); + writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); +} + +static inline bool bcm2835_dma_oob_capable(void) +{ + return IS_ENABLED(CONFIG_DMA_BCM2835_OOB); +} + static void bcm2835_dma_start_desc(struct bcm2835_chan *c) { struct virt_dma_desc *vd = vchan_next_desc(&c->vc); - struct bcm2835_desc *d; if (!vd) { c->desc = NULL; @@ -447,10 +458,41 @@ list_del(&vd->node); - c->desc = d = to_bcm2835_dma_desc(&vd->tx); + c->desc = to_bcm2835_dma_desc(&vd->tx); + if (!bcm2835_dma_oob_capable() || !vchan_oob_pulsed(vd)) + bcm2835_dma_enable_channel(c); +} - writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); - writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS); +static bool do_channel(struct bcm2835_chan *c, struct bcm2835_desc *d) +{ + struct dmaengine_desc_callback cb; + + if (running_oob()) { + if (!vchan_oob_handled(&d->vd)) + return false; + dmaengine_desc_get_callback(&d->vd.tx, &cb); + if (dmaengine_desc_callback_valid(&cb)) { + vchan_unlock(&c->vc); + dmaengine_desc_callback_invoke(&cb, NULL); + vchan_lock(&c->vc); + } + return true; + } + + if (d->cyclic) { + /* call the cyclic callback */ + vchan_cyclic_callback(&d->vd); + } else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) { + vchan_cookie_complete(&c->desc->vd); + bcm2835_dma_start_desc(c); + } + + return true; +} + +static inline bool is_base_irq_handler(void) +{ + return !bcm2835_dma_oob_capable() || running_oob(); } static irqreturn_t bcm2835_dma_callback(int irq, void *data) @@ -460,7 +502,7 @@ unsigned long flags; /* check the shared interrupt */ - if (c->irq_flags & IRQF_SHARED) { + if (is_base_irq_handler() && c->irq_flags & IRQF_SHARED) { /* check if the interrupt is enabled */ flags = readl(c->chan_base + BCM2835_DMA_CS); /* if not set then we are not the reason for the irq */ @@ -468,7 +510,8 @@ return IRQ_NONE; } - spin_lock_irqsave(&c->vc.lock, flags); + /* CAUTION: If running in-band, hard irqs are on. */ + vchan_lock_irqsave(&c->vc, flags); /* * Clear the INT flag to receive further interrupts. Keep the channel @@ -477,22 +520,27 @@ * if this IRQ handler is threaded.) If the channel is finished, it * will remain idle despite the ACTIVE flag being set. */ - writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE, - c->chan_base + BCM2835_DMA_CS); + if (is_base_irq_handler()) + writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE, + c->chan_base + BCM2835_DMA_CS); d = c->desc; + if (!d) + goto out; - if (d) { - if (d->cyclic) { - /* call the cyclic callback */ - vchan_cyclic_callback(&d->vd); - } else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) { - vchan_cookie_complete(&c->desc->vd); - bcm2835_dma_start_desc(c); - } + if (bcm2835_dma_oob_capable() && running_oob()) { + /* + * If we cannot process this from the out-of-band + * stage, schedule a callback from in-band context. + */ + if (!do_channel(c, d)) + irq_post_inband(irq); + } else { + do_channel(c, d); } - spin_unlock_irqrestore(&c->vc.lock, flags); +out: + vchan_unlock_irqrestore(&c->vc, flags); return IRQ_HANDLED; } @@ -571,7 +619,7 @@ if (ret == DMA_COMPLETE || !txstate) return ret; - spin_lock_irqsave(&c->vc.lock, flags); + vchan_lock_irqsave(&c->vc, flags); vd = vchan_find_desc(&c->vc, cookie); if (vd) { txstate->residue = @@ -592,7 +640,7 @@ txstate->residue = 0; } - spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_unlock_irqrestore(&c->vc, flags); return ret; } @@ -602,12 +650,35 @@ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); unsigned long flags; - spin_lock_irqsave(&c->vc.lock, flags); + vchan_lock_irqsave(&c->vc, flags); if (vchan_issue_pending(&c->vc) && !c->desc) bcm2835_dma_start_desc(c); - spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_unlock_irqrestore(&c->vc, flags); } + +#ifdef CONFIG_DMA_BCM2835_OOB +static int bcm2835_dma_pulse_oob(struct dma_chan *chan) +{ + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); + unsigned long flags; + int ret = -EIO; + + vchan_lock_irqsave(&c->vc, flags); + if (c->desc && vchan_oob_pulsed(&c->desc->vd)) { + bcm2835_dma_enable_channel(c); + ret = 0; + } + vchan_unlock_irqrestore(&c->vc, flags); + + return ret; +} +#else +static int bcm2835_dma_pulse_oob(struct dma_chan *chan) +{ + return -ENOTSUPP; +} +#endif static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_memcpy( struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, @@ -649,6 +720,15 @@ u32 info = BCM2835_DMA_WAIT_RESP; u32 extra = BCM2835_DMA_INT_EN; size_t frames; + + if (!bcm2835_dma_oob_capable()) { + if (flags & (DMA_OOB_INTERRUPT|DMA_OOB_PULSE)) { + dev_err(chan->device->dev, + "%s: out-of-band slave transfers disabled\n", + __func__); + return NULL; + } + } if (!is_slave_direction(direction)) { dev_err(chan->device->dev, @@ -715,7 +795,21 @@ return NULL; } - if (flags & DMA_PREP_INTERRUPT) + if (!bcm2835_dma_oob_capable()) { + if (flags & DMA_OOB_INTERRUPT) { + dev_err(chan->device->dev, + "%s: out-of-band cyclic transfers disabled\n", + __func__); + return NULL; + } + } else if (flags & DMA_OOB_PULSE) { + dev_err(chan->device->dev, + "%s: no pulse mode with out-of-band cyclic transfers\n", + __func__); + return NULL; + } + + if (flags & (DMA_PREP_INTERRUPT|DMA_OOB_INTERRUPT)) extra |= BCM2835_DMA_INT_EN; else period_len = buf_len; @@ -791,7 +885,7 @@ unsigned long flags; LIST_HEAD(head); - spin_lock_irqsave(&c->vc.lock, flags); + vchan_lock_irqsave(&c->vc, flags); /* stop DMA activity */ if (c->desc) { @@ -801,7 +895,7 @@ } vchan_get_all_descriptors(&c->vc, &head); - spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_unlock_irqrestore(&c->vc, flags); vchan_dma_desc_free_list(&c->vc, &head); return 0; @@ -912,11 +1006,13 @@ dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask); dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); + dma_cap_set(DMA_OOB, od->ddev.cap_mask); dma_cap_set(DMA_MEMCPY, od->ddev.cap_mask); od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources; od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources; od->ddev.device_tx_status = bcm2835_dma_tx_status; od->ddev.device_issue_pending = bcm2835_dma_issue_pending; + od->ddev.device_pulse_oob = bcm2835_dma_pulse_oob; od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic; od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg; od->ddev.device_prep_dma_memcpy = bcm2835_dma_prep_dma_memcpy; @@ -982,10 +1078,10 @@ continue; /* check if there are other channels that also use this irq */ - irq_flags = 0; + irq_flags = IS_ENABLED(CONFIG_DMA_BCM2835_OOB) ? IRQF_OOB : 0; for (j = 0; j <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; j++) if ((i != j) && (irq[j] == irq[i])) { - irq_flags = IRQF_SHARED; + irq_flags |= IRQF_SHARED; break; } -- Gitblit v1.6.2